Datasets and DataLoaders¶
In [172]:
# Instalacion de las librerias necesarias
%pip install transformers
%pip install torch torchvision torchaudio
%pip install opencv-python
%pip install numpy
%pip install albumentations
%pip install pillow
%pip install matplotlib
%pip install pandas
%pip install seaborn
%pip install tqdm
%pip install segmentation_models_pytorch
#%pip install sklearn
%pip install scikit-learn
Requirement already satisfied: transformers in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (4.57.3) Requirement already satisfied: filelock in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (3.20.0) Requirement already satisfied: huggingface-hub<1.0,>=0.34.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (0.36.0) Requirement already satisfied: numpy>=1.17 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (2.2.6) Requirement already satisfied: packaging>=20.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (25.0) Requirement already satisfied: pyyaml>=5.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (6.0.3) Requirement already satisfied: regex!=2019.12.17 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (2025.11.3) Requirement already satisfied: requests in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (2.32.5) Requirement already satisfied: tokenizers<=0.23.0,>=0.22.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (0.22.1) Requirement already satisfied: safetensors>=0.4.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (0.7.0) Requirement already satisfied: tqdm>=4.27 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from transformers) (4.67.1) Requirement already satisfied: fsspec>=2023.5.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub<1.0,>=0.34.0->transformers) (2025.12.0) Requirement already satisfied: typing-extensions>=3.7.4.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub<1.0,>=0.34.0->transformers) (4.15.0) Requirement already satisfied: colorama in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from tqdm>=4.27->transformers) (0.4.6) Requirement already satisfied: charset_normalizer<4,>=2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->transformers) (3.4.4) Requirement already satisfied: idna<4,>=2.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->transformers) (3.11) Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->transformers) (2.6.1) Requirement already satisfied: certifi>=2017.4.17 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->transformers) (2025.11.12) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: torch in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.9.1) Requirement already satisfied: torchvision in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (0.24.1) Requirement already satisfied: torchaudio in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.9.1) Requirement already satisfied: filelock in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.20.0) Requirement already satisfied: typing-extensions>=4.10.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (4.15.0) Requirement already satisfied: sympy>=1.13.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (1.14.0) Requirement already satisfied: networkx>=2.5.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.6.1) Requirement already satisfied: jinja2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.1.6) Requirement already satisfied: fsspec>=0.8.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (2025.12.0) Requirement already satisfied: setuptools in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (80.9.0) Requirement already satisfied: numpy in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torchvision) (2.2.6) Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torchvision) (12.0.0) Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from sympy>=1.13.3->torch) (1.3.0) Requirement already satisfied: MarkupSafe>=2.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from jinja2->torch) (3.0.3) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: opencv-python in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (4.12.0.88) Requirement already satisfied: numpy<2.3.0,>=2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from opencv-python) (2.2.6) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: numpy in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.2.6) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: albumentations in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.0.8) Requirement already satisfied: numpy>=1.24.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (2.2.6) Requirement already satisfied: scipy>=1.10.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (1.16.3) Requirement already satisfied: PyYAML in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (6.0.3) Requirement already satisfied: pydantic>=2.9.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (2.12.5) Requirement already satisfied: albucore==0.0.24 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (0.0.24) Requirement already satisfied: opencv-python-headless>=4.9.0.80 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (4.12.0.88) Requirement already satisfied: stringzilla>=3.10.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albucore==0.0.24->albumentations) (4.4.0) Requirement already satisfied: simsimd>=5.9.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albucore==0.0.24->albumentations) (6.5.3) Requirement already satisfied: annotated-types>=0.6.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (0.7.0) Requirement already satisfied: pydantic-core==2.41.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (2.41.5) Requirement already satisfied: typing-extensions>=4.14.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (4.15.0) Requirement already satisfied: typing-inspection>=0.4.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (0.4.2) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: pillow in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (12.0.0) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: matplotlib in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (3.10.8) Requirement already satisfied: contourpy>=1.0.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (1.3.3) Requirement already satisfied: cycler>=0.10 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (4.61.0) Requirement already satisfied: kiwisolver>=1.3.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (1.4.9) Requirement already satisfied: numpy>=1.23 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (2.2.6) Requirement already satisfied: packaging>=20.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (25.0) Requirement already satisfied: pillow>=8 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (12.0.0) Requirement already satisfied: pyparsing>=3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (3.2.5) Requirement already satisfied: python-dateutil>=2.7 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (2.9.0.post0) Requirement already satisfied: six>=1.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from python-dateutil>=2.7->matplotlib) (1.17.0) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: pandas in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.3.3) Requirement already satisfied: numpy>=1.26.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas) (2.2.6) Requirement already satisfied: python-dateutil>=2.8.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas) (2.9.0.post0) Requirement already satisfied: pytz>=2020.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas) (2025.2) Requirement already satisfied: tzdata>=2022.7 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas) (2025.2) Requirement already satisfied: six>=1.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: seaborn in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (0.13.2) Requirement already satisfied: numpy!=1.24.0,>=1.20 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from seaborn) (2.2.6) Requirement already satisfied: pandas>=1.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from seaborn) (2.3.3) Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from seaborn) (3.10.8) Requirement already satisfied: contourpy>=1.0.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.3.3) Requirement already satisfied: cycler>=0.10 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (4.61.0) Requirement already satisfied: kiwisolver>=1.3.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.4.9) Requirement already satisfied: packaging>=20.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (25.0) Requirement already satisfied: pillow>=8 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (12.0.0) Requirement already satisfied: pyparsing>=3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (3.2.5) Requirement already satisfied: python-dateutil>=2.7 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (2.9.0.post0) Requirement already satisfied: pytz>=2020.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas>=1.2->seaborn) (2025.2) Requirement already satisfied: tzdata>=2022.7 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pandas>=1.2->seaborn) (2025.2) Requirement already satisfied: six>=1.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.4->seaborn) (1.17.0) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: tqdm in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (4.67.1) Requirement already satisfied: colorama in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from tqdm) (0.4.6) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: segmentation_models_pytorch in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (0.5.0) Requirement already satisfied: huggingface-hub>=0.24 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (0.36.0) Requirement already satisfied: numpy>=1.19.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (2.2.6) Requirement already satisfied: pillow>=8 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (12.0.0) Requirement already satisfied: safetensors>=0.3.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (0.7.0) Requirement already satisfied: timm>=0.9 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (1.0.22) Requirement already satisfied: torch>=1.8 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (2.9.1) Requirement already satisfied: torchvision>=0.9 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (0.24.1) Requirement already satisfied: tqdm>=4.42.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from segmentation_models_pytorch) (4.67.1) Requirement already satisfied: filelock in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (3.20.0) Requirement already satisfied: fsspec>=2023.5.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (2025.12.0) Requirement already satisfied: packaging>=20.9 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (25.0) Requirement already satisfied: pyyaml>=5.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (6.0.3) Requirement already satisfied: requests in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (2.32.5) Requirement already satisfied: typing-extensions>=3.7.4.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from huggingface-hub>=0.24->segmentation_models_pytorch) (4.15.0) Requirement already satisfied: sympy>=1.13.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch>=1.8->segmentation_models_pytorch) (1.14.0) Requirement already satisfied: networkx>=2.5.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch>=1.8->segmentation_models_pytorch) (3.6.1) Requirement already satisfied: jinja2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch>=1.8->segmentation_models_pytorch) (3.1.6) Requirement already satisfied: setuptools in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch>=1.8->segmentation_models_pytorch) (80.9.0) Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from sympy>=1.13.3->torch>=1.8->segmentation_models_pytorch) (1.3.0) Requirement already satisfied: colorama in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from tqdm>=4.42.1->segmentation_models_pytorch) (0.4.6) Requirement already satisfied: MarkupSafe>=2.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from jinja2->torch>=1.8->segmentation_models_pytorch) (3.0.3) Requirement already satisfied: charset_normalizer<4,>=2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->huggingface-hub>=0.24->segmentation_models_pytorch) (3.4.4) Requirement already satisfied: idna<4,>=2.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->huggingface-hub>=0.24->segmentation_models_pytorch) (3.11) Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->huggingface-hub>=0.24->segmentation_models_pytorch) (2.6.1) Requirement already satisfied: certifi>=2017.4.17 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from requests->huggingface-hub>=0.24->segmentation_models_pytorch) (2025.11.12) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: scikit-learn in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (1.8.0) Requirement already satisfied: numpy>=1.24.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-learn) (2.2.6) Requirement already satisfied: scipy>=1.10.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-learn) (1.16.3) Requirement already satisfied: joblib>=1.3.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-learn) (1.5.2) Requirement already satisfied: threadpoolctl>=3.2.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-learn) (3.6.0) Note: you may need to restart the kernel to use updated packages.
In [173]:
# impotacion de librerias
import json, os, torch, cv2, numpy as np, albumentations as A
from PIL import Image; from matplotlib import pyplot as plt
from glob import glob; from PIL import ImageFile
from torch.utils.data import random_split, Dataset, DataLoader
from albumentations.pytorch import ToTensorV2
import random
import sklearn.metrics as metrics
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import confusion_matrix, roc_auc_score, mean_squared_error, r2_score
import os
import numpy as np
import pandas as pd
import albumentations as A
from albumentations.pytorch import ToTensorV2
ImageFile.LOAD_TRUNCATED_IMAGES = True
import segmentation_models_pytorch as smp, time
from tqdm import tqdm
from torch.nn import functional as F
import cv2
import matplotlib.pyplot as plt
import torch
import numpy as np
from PIL import Image
from typing import List, Tuple, Optional
import matplotlib.patches as mpatches
import random
import matplotlib.pyplot as plt
import math
from torchvision import transforms as tfs
import torch
import torch.nn as nn
import time
In [174]:
# Exploracion del archivo CSV con los labels
path_csv = "C:\\Users\\pc\\Desktop\\Proyecto_Segmentacion\\dataset\\labels.csv" # ajusta a tu ruta real
df = pd.read_csv(path_csv)
# #limpieza de los nombres de las columnas
# df.columns = df.columns.str.strip().str.replace('\ufeff', '')
# print(df.head())
# print(df.tail())
# print(df.shape)
# col = "label_list" # nombre correcto
In [175]:
# Copia de seguridad
df2 = df.copy()
df2 = pd.read_csv(path_csv)
#limpieza de los nombres de las columnas
df2.columns = df2.columns.str.strip().str.replace('\ufeff', '')
print(df2.head())
print(df2.tail())
print(df2.shape)
Unnamed: 0 label_list
0 0 background
1 1 accessories
2 2 bag
3 3 belt
4 4 blazer
Unnamed: 0 label_list
54 54 top
55 55 vest
56 56 wallet
57 57 watch
58 58 wedges
(59, 2)
In [176]:
col = "label_list" # nombre correcto
# Mapeo SEMÁNTICO (texto → clase limpia)
mapping = {
# --- TOPWEAR (tops + outerwear juntos) ---
"blazer": "topwear",
"jacket": "topwear",
"coat": "topwear",
"cape": "topwear",
"cardigan": "topwear",
"suit": "topwear",
"t-shirt": "topwear",
"shirt": "topwear",
"top": "topwear",
"sweater": "topwear",
"hoodie": "topwear",
"blouse": "topwear",
"bodysuit": "topwear",
"sweatshirt": "topwear",
"vest": "topwear",
# --- LOWERWEAR ---
"pants": "lowerwear",
"jeans": "lowerwear",
"leggings": "lowerwear",
"skirt": "lowerwear",
"shorts": "lowerwear",
"panties": "lowerwear",
"tights": "lowerwear",
# --- DRESSES ---
"dress": "dress",
"romper": "dress",
# --- FOOTWEAR ---
"boots": "footwear",
"sneakers": "footwear",
"flats": "footwear",
"heels": "footwear",
"loafers": "footwear",
"sandals": "footwear",
"wedges": "footwear",
"pumps": "footwear",
"clogs": "footwear",
"shoes": "footwear",
# --- BODY (reabierto) ---
"hair": "body",
"skin": "body",
# --- BACKGROUND ---
"background": "background"
}
# Aplicar mapeo (todo lo no definido → ignore)
df2["clean_label"] = df2["label_list"].map(mapping).fillna("ignore")
# Mapeo NUMÉRICO FINAL (coherente con clean_label)
numeric_mapping = {
"background": 0,
"topwear": 1,
"lowerwear": 2,
"dress": 3,
"footwear": 4,
"body": 5,
"ignore": 255
}
df2["numeric_label"] = df2["clean_label"].map(numeric_mapping)
# Etiqueta concatenada (debug / visualización)
df2["concatenated_label"] = df2.apply(
lambda row: f"{row['numeric_label']}: {row['clean_label']}",
axis=1
)
# Guardar
df2.to_csv("dataset/label_list_clean_with_numeric.csv", index=False)
# Debug
print(df2[['label_list', 'clean_label', 'numeric_label', 'concatenated_label']].head(20))
print("\nDistribución de clases:")
print(df2['numeric_label'].value_counts().sort_index())
label_list clean_label numeric_label concatenated_label 0 background background 0 0: background 1 accessories ignore 255 255: ignore 2 bag ignore 255 255: ignore 3 belt ignore 255 255: ignore 4 blazer topwear 1 1: topwear 5 blouse topwear 1 1: topwear 6 bodysuit topwear 1 1: topwear 7 boots footwear 4 4: footwear 8 bra ignore 255 255: ignore 9 bracelet ignore 255 255: ignore 10 cape topwear 1 1: topwear 11 cardigan topwear 1 1: topwear 12 clogs footwear 4 4: footwear 13 coat topwear 1 1: topwear 14 dress dress 3 3: dress 15 earrings ignore 255 255: ignore 16 flats footwear 4 4: footwear 17 glasses ignore 255 255: ignore 18 gloves ignore 255 255: ignore 19 hair body 5 5: body Distribución de clases: numeric_label 0 1 1 15 2 7 3 2 4 10 5 2 255 22 Name: count, dtype: int64
In [177]:
df2
Out[177]:
| Unnamed: 0 | label_list | clean_label | numeric_label | concatenated_label | |
|---|---|---|---|---|---|
| 0 | 0 | background | background | 0 | 0: background |
| 1 | 1 | accessories | ignore | 255 | 255: ignore |
| 2 | 2 | bag | ignore | 255 | 255: ignore |
| 3 | 3 | belt | ignore | 255 | 255: ignore |
| 4 | 4 | blazer | topwear | 1 | 1: topwear |
| 5 | 5 | blouse | topwear | 1 | 1: topwear |
| 6 | 6 | bodysuit | topwear | 1 | 1: topwear |
| 7 | 7 | boots | footwear | 4 | 4: footwear |
| 8 | 8 | bra | ignore | 255 | 255: ignore |
| 9 | 9 | bracelet | ignore | 255 | 255: ignore |
| 10 | 10 | cape | topwear | 1 | 1: topwear |
| 11 | 11 | cardigan | topwear | 1 | 1: topwear |
| 12 | 12 | clogs | footwear | 4 | 4: footwear |
| 13 | 13 | coat | topwear | 1 | 1: topwear |
| 14 | 14 | dress | dress | 3 | 3: dress |
| 15 | 15 | earrings | ignore | 255 | 255: ignore |
| 16 | 16 | flats | footwear | 4 | 4: footwear |
| 17 | 17 | glasses | ignore | 255 | 255: ignore |
| 18 | 18 | gloves | ignore | 255 | 255: ignore |
| 19 | 19 | hair | body | 5 | 5: body |
| 20 | 20 | hat | ignore | 255 | 255: ignore |
| 21 | 21 | heels | footwear | 4 | 4: footwear |
| 22 | 22 | hoodie | topwear | 1 | 1: topwear |
| 23 | 23 | intimate | ignore | 255 | 255: ignore |
| 24 | 24 | jacket | topwear | 1 | 1: topwear |
| 25 | 25 | jeans | lowerwear | 2 | 2: lowerwear |
| 26 | 26 | jumper | ignore | 255 | 255: ignore |
| 27 | 27 | leggings | lowerwear | 2 | 2: lowerwear |
| 28 | 28 | loafers | footwear | 4 | 4: footwear |
| 29 | 29 | necklace | ignore | 255 | 255: ignore |
| 30 | 30 | panties | lowerwear | 2 | 2: lowerwear |
| 31 | 31 | pants | lowerwear | 2 | 2: lowerwear |
| 32 | 32 | pumps | footwear | 4 | 4: footwear |
| 33 | 33 | purse | ignore | 255 | 255: ignore |
| 34 | 34 | ring | ignore | 255 | 255: ignore |
| 35 | 35 | romper | dress | 3 | 3: dress |
| 36 | 36 | sandals | footwear | 4 | 4: footwear |
| 37 | 37 | scarf | ignore | 255 | 255: ignore |
| 38 | 38 | shirt | topwear | 1 | 1: topwear |
| 39 | 39 | shoes | footwear | 4 | 4: footwear |
| 40 | 40 | shorts | lowerwear | 2 | 2: lowerwear |
| 41 | 41 | skin | body | 5 | 5: body |
| 42 | 42 | skirt | lowerwear | 2 | 2: lowerwear |
| 43 | 43 | sneakers | footwear | 4 | 4: footwear |
| 44 | 44 | socks | ignore | 255 | 255: ignore |
| 45 | 45 | stockings | ignore | 255 | 255: ignore |
| 46 | 46 | suit | topwear | 1 | 1: topwear |
| 47 | 47 | sunglasses | ignore | 255 | 255: ignore |
| 48 | 48 | sweater | topwear | 1 | 1: topwear |
| 49 | 49 | sweatshirt | topwear | 1 | 1: topwear |
| 50 | 50 | swimwear | ignore | 255 | 255: ignore |
| 51 | 51 | t-shirt | topwear | 1 | 1: topwear |
| 52 | 52 | tie | ignore | 255 | 255: ignore |
| 53 | 53 | tights | lowerwear | 2 | 2: lowerwear |
| 54 | 54 | top | topwear | 1 | 1: topwear |
| 55 | 55 | vest | topwear | 1 | 1: topwear |
| 56 | 56 | wallet | ignore | 255 | 255: ignore |
| 57 | 57 | watch | ignore | 255 | 255: ignore |
| 58 | 58 | wedges | footwear | 4 | 4: footwear |
In [178]:
df2.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 59 entries, 0 to 58 Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 59 non-null int64 1 label_list 59 non-null object 2 clean_label 59 non-null object 3 numeric_label 59 non-null int64 4 concatenated_label 59 non-null object dtypes: int64(2), object(3) memory usage: 2.4+ KB
In [179]:
df2['numeric_label'].value_counts
Out[179]:
<bound method IndexOpsMixin.value_counts of 0 0 1 255 2 255 3 255 4 1 5 1 6 1 7 4 8 255 9 255 10 1 11 1 12 4 13 1 14 3 15 255 16 4 17 255 18 255 19 5 20 255 21 4 22 1 23 255 24 1 25 2 26 255 27 2 28 4 29 255 30 2 31 2 32 4 33 255 34 255 35 3 36 4 37 255 38 1 39 4 40 2 41 5 42 2 43 4 44 255 45 255 46 1 47 255 48 1 49 1 50 255 51 1 52 255 53 2 54 1 55 1 56 255 57 255 58 4 Name: numeric_label, dtype: int64>
In [180]:
train_tf = A.Compose([
# --- Resize y Random Crop (evita que modelo aprenda tamaño fijo) ---
# A.Resize(320, 320),
# A.RandomCrop(256, 256, p=0.8),
A.RandomResizedCrop(
size=(256, 256),
scale=(0.7, 1.0),
ratio=(0.75, 1.33),
p=1.0
),
# --- Transformaciones geométricas más robustas ---
A.OneOf([
A.ShiftScaleRotate(
shift_limit=0.1,
scale_limit=0.2,
rotate_limit=15,
border_mode=cv2.BORDER_CONSTANT,
value=0,
mask_value=255,
p=1.0
),
A.GridDistortion(
num_steps=5,
distort_limit=0.3,
border_mode=cv2.BORDER_CONSTANT,
value=0,
mask_value=255,
p=0.3
),
], p=0.8),
A.HorizontalFlip(p=0.5),
# --- Color y textura más agresivos ---
A.OneOf([
A.RandomBrightnessContrast(
brightness_limit=0.3,
contrast_limit=0.3
),
A.HueSaturationValue(
hue_shift_limit=20,
sat_shift_limit=30,
val_shift_limit=20
),
A.RGBShift(
r_shift_limit=20,
g_shift_limit=20,
b_shift_limit=20
),
], p=0.5),
# --- Ruido y desenfoque ---
A.OneOf([
A.GaussianBlur(blur_limit=(3, 7)),
A.MedianBlur(blur_limit=5),
A.MotionBlur(blur_limit=7),
], p=0.3),
A.GaussNoise(var_limit=(10.0, 40.0), p=0.2),
# --- Compresión y calidad (simula diferentes fuentes) ---
A.ImageCompression(
quality_lower=60,
quality_upper=95,
p=0.2
),
# --- Cutout / CoarseDropout (regularización espacial) ---
A.CoarseDropout(
max_holes=8,
max_height=32,
max_width=32,
min_holes=1,
min_height=8,
min_width=8,
fill_value=0,
mask_fill_value=255,
p=0.3
),
# --- Normalización ---
A.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
),
ToTensorV2()
])
val_tf = A.Compose([
A.Resize(256, 256),
A.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
),
ToTensorV2()
])
c:\Users\pc\Desktop\Proyecto_Segmentacion\.venv\Lib\site-packages\albumentations\core\validation.py:114: UserWarning: ShiftScaleRotate is a special case of Affine transform. Please use Affine transform instead. original_init(self, **validated_kwargs) C:\Users\pc\AppData\Local\Temp\ipykernel_12992\3931023381.py:15: UserWarning: Argument(s) 'value, mask_value' are not valid for transform ShiftScaleRotate A.ShiftScaleRotate( C:\Users\pc\AppData\Local\Temp\ipykernel_12992\3931023381.py:25: UserWarning: Argument(s) 'value, mask_value' are not valid for transform GridDistortion A.GridDistortion( C:\Users\pc\AppData\Local\Temp\ipykernel_12992\3931023381.py:62: UserWarning: Argument(s) 'var_limit' are not valid for transform GaussNoise A.GaussNoise(var_limit=(10.0, 40.0), p=0.2), C:\Users\pc\AppData\Local\Temp\ipykernel_12992\3931023381.py:65: UserWarning: Argument(s) 'quality_lower, quality_upper' are not valid for transform ImageCompression A.ImageCompression( C:\Users\pc\AppData\Local\Temp\ipykernel_12992\3931023381.py:72: UserWarning: Argument(s) 'max_holes, max_height, max_width, min_holes, min_height, min_width, fill_value, mask_fill_value' are not valid for transform CoarseDropout A.CoarseDropout(
In [181]:
root = "C:\\Users\\pc\\Desktop\\Proyecto_Segmentacion\\dataset"
csv_labels_path = "C:\\Users\\pc\\Desktop\\Proyecto_Segmentacion\\dataset\\label_list_clean_with_numeric.csv"
In [182]:
class CustomSegmentationDataset(Dataset):
def __init__(self, root, transformations=None, csv_labels_path=None):
# Paths
self.im_paths = sorted(glob(os.path.join(root, "png_images", "IMAGES", "*.png")))
self.gt_paths = sorted(glob(os.path.join(root, "png_masks", "MASKS", "*.png")))
assert len(self.im_paths) == len(self.gt_paths), \
"Cantidad de imágenes y máscaras no coincide."
self.transformations = transformations
self.ignore_index = 255
# ============================
# 1. CSV limpio
# ============================
self.id_to_numeric = dict(zip(df2["Unnamed: 0"], df2["numeric_label"]))
# id original → label limpio
self.id_to_clean = dict(zip(df2["Unnamed: 0"], df2["clean_label"]))
# Obtener clases válidas (excluyendo ignore)
valid_classes_df2 = df2[df2["numeric_label"] != self.ignore_index].copy()
# Info del dataset
self.n_cls = len(
sorted(df2[df2["numeric_label"] != self.ignore_index]["numeric_label"].unique())
)
# Usar con sus ids de su base
self.label_to_idx = dict(zip(valid_classes_df2["clean_label"], valid_classes_df2["numeric_label"])
)
# Mapeo inverso para decodificar predicciones
self.idx_to_label = {idx: cls for cls, idx in self.label_to_idx.items()}
self.n_cls = len(self.label_to_idx)
def __len__(self):
return len(self.im_paths)
def __getitem__(self, idx):
im = np.array(Image.open(self.im_paths[idx]).convert("RGB"))
gt = np.array(Image.open(self.gt_paths[idx]))
# ============================
# 2. Remapeo con ignore_index
# ============================
remapped = np.full_like(gt, fill_value=self.ignore_index, dtype=np.int64)
# Aplicar el mapeo directamente
for original_id, numeric_label in self.id_to_numeric.items():
remapped[gt == original_id] = numeric_label
gt = remapped
# Asegurar que gt sea int64
gt = gt.astype(np.int64)
# Transformaciones
if self.transformations:
augmented = self.transformations(image=im, mask=gt)
im, gt = augmented["image"], augmented["mask"]
# Asegurar tipo después de transformaciones
if torch.is_tensor(gt):
gt = gt.long() # Convertir a Long
elif isinstance(gt, np.ndarray):
gt = gt.astype(np.int64)
# Asegurar que las imágenes estén en float32
if torch.is_tensor(im):
im = im.float()
return im, gt
def get_class_names(self):
"""Retorna los nombres de las clases en orden"""
return [self.idx_to_label[i] for i in range(self.n_cls)]
In [183]:
def get_dls(
root,
train_tf,
val_tf,
bs,
split=(0.8, 0.1, 0.1),
ns=2,
csv_labels_path=None,
seed=42,
device="cpu"
):
# Dataset base (solo info)
base_ds = CustomSegmentationDataset(
root=root,
transformations=None,
csv_labels_path=csv_labels_path
)
dataset_info = {
'n_cls': base_ds.n_cls,
'ignore_index': base_ds.ignore_index,
'class_names': base_ds.get_class_names(),
'label_to_idx': base_ds.label_to_idx,
'idx_to_label': base_ds.idx_to_label
}
print(dataset_info)
# reproducibilidad
generator = torch.Generator().manual_seed(seed)
tr_len = int(len(base_ds) * split[0])
val_len = int(len(base_ds) * split[1])
test_len = len(base_ds) - tr_len - val_len
# tr_ds, val_ds, test_ds = torch.utils.data.random_split(
# base_ds, [tr_len, val_len, test_len], generator=generator
# )
indices = torch.randperm(len(base_ds), generator=generator)
tr_idx = indices[:tr_len]
val_idx = indices[tr_len:tr_len + val_len]
test_idx = indices[tr_len + val_len:]
print(f"\nDIVISIÓN DEL DATASET (seed={seed}):")
print(f"Train: {len(tr_idx)} muestras ({split[0]*100:.1f}%)")
print(f"Val: {len(val_idx)} muestras ({split[1]*100:.1f}%)")
print(f"Test: {len(test_idx)} muestras ({split[2]*100:.1f}%)")
# =====================================================
# 3. Crear datasets SEPARADOS con transforms correctos
# =====================================================
# Datasets con transforms correctos
train_ds = torch.utils.data.Subset(
CustomSegmentationDataset(root, train_tf, csv_labels_path),
tr_idx
)
val_ds = torch.utils.data.Subset(
CustomSegmentationDataset(root, val_tf, csv_labels_path),
val_idx
)
test_ds = torch.utils.data.Subset(
CustomSegmentationDataset(root, val_tf, csv_labels_path),
test_idx
)
# =====================================================
# 4. Dataloaders
# =====================================================
pin = (device == "cuda")
tr_dl = DataLoader(train_ds, bs, shuffle=True,
num_workers=ns, pin_memory=pin,
persistent_workers=(ns > 0))
val_dl = DataLoader(val_ds, bs, shuffle=False,
num_workers=ns, pin_memory=pin,
persistent_workers=(ns > 0))
test_dl = DataLoader(test_ds, 1, shuffle=False,
num_workers=ns, pin_memory=pin,
persistent_workers=(ns > 0))
# VERIFICAR DISTRIBUCIÓN DE CLASES EN SPLITS
# ============================================
def get_class_distribution(subset):
"""Calcula distribución de clases en un subset"""
all_masks = []
for i in range(min(100, len(subset))): # Muestrear hasta 100
_, mask = subset[i]
if torch.is_tensor(mask):
mask = mask.numpy()
all_masks.append(mask.flatten())
if all_masks:
concatenated = np.concatenate(all_masks)
unique, counts = np.unique(concatenated, return_counts=True)
dist = dict(zip(unique, counts))
# Convertir índices a nombres de clase
dist_named = {}
for idx, count in dist.items():
if idx == base_ds.ignore_index:
dist_named['ignore'] = count
elif idx in base_ds.idx_to_label:
dist_named[base_ds.idx_to_label[idx]] = count
else:
dist_named[str(idx)] = count
return dist_named
return {}
print("\nDistribución aproximada de clases (primeras 100 muestras):")
print("Train:", get_class_distribution(train_ds))
print("Val: ", get_class_distribution(val_ds))
print("Test: ", get_class_distribution(test_ds))
print("\n" + "=" * 50)
print("DATALOADERS CREADOS EXITOSAMENTE")
print("=" * 50)
return tr_dl, val_dl, test_dl, dataset_info
In [184]:
device = "cuda" if torch.cuda.is_available() else "cpu"
tr_dl, val_dl, test_dl, info = get_dls(
root=root,
train_tf=train_tf,
val_tf=val_tf,
bs=4,
ns=0,
csv_labels_path=csv_labels_path,
device=device
)
{'n_cls': 6, 'ignore_index': 255, 'class_names': ['background', 'topwear', 'lowerwear', 'dress', 'footwear', 'body'], 'label_to_idx': {'background': 0, 'topwear': 1, 'footwear': 4, 'dress': 3, 'body': 5, 'lowerwear': 2}, 'idx_to_label': {0: 'background', 1: 'topwear', 4: 'footwear', 3: 'dress', 5: 'body', 2: 'lowerwear'}}
DIVISIÓN DEL DATASET (seed=42):
Train: 800 muestras (80.0%)
Val: 100 muestras (10.0%)
Test: 100 muestras (10.0%)
Distribución aproximada de clases (primeras 100 muestras):
Train: {'background': np.int64(4805028), 'topwear': np.int64(655546), 'lowerwear': np.int64(354726), 'dress': np.int64(233653), 'footwear': np.int64(48321), 'body': np.int64(297725), 'ignore': np.int64(158601)}
Val: {'background': np.int64(5037874), 'topwear': np.int64(486014), 'lowerwear': np.int64(299220), 'dress': np.int64(224666), 'footwear': np.int64(73741), 'body': np.int64(274670), 'ignore': np.int64(157415)}
Test: {'background': np.int64(5058909), 'topwear': np.int64(547670), 'lowerwear': np.int64(304042), 'dress': np.int64(157740), 'footwear': np.int64(65676), 'body': np.int64(265605), 'ignore': np.int64(153958)}
==================================================
DATALOADERS CREADOS EXITOSAMENTE
==================================================
In [185]:
# índice = clase
CLASS_COLORS = [
[0, 0, 0], # 0 background → negro
[220, 20, 60], # 1 topwear → rojo (crimson)
[30, 144, 255], # 2 lowerwear → azul
[255, 165, 0], # 3 dress → naranja
[138, 43, 226], # 4 footwear → violeta
[46, 139, 87], # 5 body → verde (sea green)
]
# Leyenda alineada con el dataset
CLASS_LEGEND = [
("background", "negro", 0),
("topwear", "rojo", 1),
("lowerwear", "azul", 2),
("dress", "naranja", 3),
("footwear", "violeta", 4),
("body", "verde", 5),
]
VISUALIZACION DE LA DATA¶
In [186]:
# ---------------------------------------------------------
# Invierte normalización ImageNet → devuelve imagen RGB uint8
# ---------------------------------------------------------
def to_numpy_image(t):
inv = tfs.Compose([
tfs.Normalize(mean=[0,0,0], std=[1/0.229, 1/0.224, 1/0.225]),
tfs.Normalize(mean=[-0.485, -0.456, -0.406], std=[1,1,1])
])
t = inv(t)
t = (t * 255).clamp(0,255).byte().cpu().permute(1,2,0).numpy()
return t
# ---------------------------------------------------------
# Convierte máscara (tensor HxW con clases) a imagen visible
# ---------------------------------------------------------
def mask_to_rgb(mask, n_cls, ignore_index=255):
"""
Convierte una máscara HxW (clases) a RGB usando colores fijos
Args:
mask: Tensor o numpy array de forma (H, W)
n_cls: Número de clases válidas
ignore_index: Valor para píxeles ignorados (default: 255)
Returns:
RGB image de forma (H, W, 3)
"""
if torch.is_tensor(mask):
mask = mask.cpu().numpy()
h, w = mask.shape
rgb = np.zeros((h, w, 3), dtype=np.int64)
for cls_idx in range(n_cls):
rgb[mask == cls_idx] = CLASS_COLORS[cls_idx]
# ignore_index → gris oscuro (para distinguir del background)
rgb[mask == ignore_index] = [64, 64, 64]
return rgb
# ---------------------------------------------------------
# Plot helper
# ---------------------------------------------------------
def plot(ax, image, title=""):
ax.imshow(image)
ax.set_title(title)
ax.axis("off")
# ---------------------------------------------------------
# Versión 1: Visualizar dataset original
# ---------------------------------------------------------
def visualize_dataset(dataset, n_ims=8):
"""
Visualiza muestras del dataset original (CustomSegmentationDataset)
"""
import math
total_plots = n_ims * 2
cols = 4
rows = math.ceil(total_plots / cols)
fig, axs = plt.subplots(rows, cols, figsize=(20, rows * 4))
axs = axs.flatten()
# Seleccionar índices aleatorios
indices = random.sample(range(len(dataset)), n_ims)
i = 0
for idx in indices:
im, gt = dataset[idx]
# Convertir imagen y máscara
rgb = to_numpy_image(im.float())
gt_img = mask_to_rgb(gt, dataset.n_cls, dataset.ignore_index)
plot(axs[i], rgb, f"Imagen {idx}")
i += 1
plot(axs[i], gt_img, f"Máscara (clases {np.unique(gt)})")
i += 1
if i >= len(axs):
break
# Ocultar ejes vacíos
for j in range(i, len(axs)):
axs[j].axis('off')
plt.suptitle(f"Dataset - {n_cls} clases | ignore_index={dataset.ignore_index}", fontsize=16)
plt.tight_layout()
plt.show()
# Mostrar estadísticas de las muestras visualizadas
print("=" * 60)
print(f"VISUALIZACIÓN - {n_ims} muestras del dataset")
print("=" * 60)
for idx in indices:
im, gt = dataset[idx]
unique_vals = torch.unique(gt) if torch.is_tensor(gt) else np.unique(gt)
valid_classes = [v for v in unique_vals if v != dataset.ignore_index and v < dataset.n_cls]
ignore_pixels = np.sum(gt == dataset.ignore_index) if hasattr(gt, '__len__') else 0
print(f"Muestra {idx}: Clases presentes: {valid_classes}, Píxeles ignorados: {ignore_pixels}")
# ---------------------------------------------------------
# Versión 2: Visualizar Subset (de DataLoader)
# ---------------------------------------------------------
def visualize_subset(subset, n_ims=8):
"""
Visualiza muestras de un Subset (como tr_dl.dataset, val_dl.dataset)
"""
import math
total_plots = n_ims * 2
cols = 4
rows = math.ceil(total_plots / cols)
fig, axs = plt.subplots(rows, cols, figsize=(20, rows * 4))
axs = axs.flatten()
# Seleccionar índices aleatorios dentro del subset
indices = random.sample(range(len(subset)), n_ims)
i = 0
for plot_idx, subset_idx in enumerate(indices):
# Obtener muestra del subset
im, gt = subset[subset_idx]
# Convertir imagen y máscara
rgb = to_numpy_image(im.float())
# Necesitamos acceder al dataset original para obtener n_cls e ignore_index
if hasattr(subset, 'dataset') and hasattr(subset.dataset, 'n_cls'):
gt_img = mask_to_rgb(gt, subset.dataset.n_cls, subset.dataset.ignore_index)
else:
# Fallback si no podemos acceder al dataset original
gt_img = mask_to_rgb(gt, n_cls, 255)
plot(axs[i], rgb, f"Imagen {plot_idx+1}")
i += 1
plot(axs[i], gt_img, f"Máscara {plot_idx+1}")
i += 1
if i >= len(axs):
break
# Ocultar ejes vacíos
for j in range(i, len(axs)):
axs[j].axis('off')
plt.suptitle(f"Subset - {n_cls} clases", fontsize=16)
plt.tight_layout()
plt.show()
# ---------------------------------------------------------
# Versión 3: Visualizar DataLoader (batch)
# ---------------------------------------------------------
def visualize_dataloader(dataloader, n_batches=1):
"""
Visualiza batches completos de un DataLoader
"""
for batch_idx, (images, masks) in enumerate(dataloader):
if batch_idx >= n_batches:
break
batch_size = images.shape[0]
cols = 4
rows = math.ceil(batch_size * 2 / cols)
fig, axs = plt.subplots(rows, cols, figsize=(20, rows * 4))
axs = axs.flatten()
i = 0
for sample_idx in range(batch_size):
img = images[sample_idx]
mask = masks[sample_idx]
rgb = to_numpy_image(img.float())
# Acceder a n_cls desde el dataset
if hasattr(dataloader.dataset, 'dataset'):
gt_img = mask_to_rgb(mask, dataloader.dataset.dataset.n_cls,
dataloader.dataset.dataset.ignore_index)
else:
gt_img = mask_to_rgb(mask, n_cls, 255)
plot(axs[i], rgb, f"Batch {batch_idx}, Img {sample_idx}")
i += 1
plot(axs[i], gt_img, f"Mask {sample_idx}")
i += 1
if i >= len(axs):
break
# Ocultar ejes vacíos
for j in range(i, len(axs)):
axs[j].axis('off')
plt.suptitle(f"Batch {batch_idx} - Shape: {images.shape}", fontsize=16)
plt.tight_layout()
plt.show()
# Estadísticas del batch
print(f"\nBatch {batch_idx}:")
print(f" Images shape: {images.shape}")
print(f" Masks shape: {masks.shape}")
unique_vals = torch.unique(masks)
print(f" Unique mask values: {unique_vals.tolist()}")
for val in unique_vals:
count = (masks == val).sum().item()
if val == 255:
print(f" ignore (255): {count} píxeles")
elif val < n_cls:
print(f" clase {val}: {count} píxeles")
# Asegurarnos de que n_cls e ignore_index estén definidos en el scope global
if 'n_cls' not in globals():
# Preferimos tomarlo del dict `info` si está disponible
try:
n_cls = info.get('n_cls', None)
except Exception:
n_cls = None
if n_cls is None:
# Fallback: usar el número de class_names si existe, o un valor por defecto razonable
n_cls = len(info.get('class_names', [])) if isinstance(info, dict) and 'class_names' in info else 6
if 'ignore_index' not in globals():
try:
ignore_index = info.get('ignore_index', 255)
except Exception:
ignore_index = 255
print("\n" + "=" * 60)
print("VISUALIZANDO SUBSET DE ENTRENAMIENTO")
print("=" * 60)
visualize_subset(tr_dl.dataset, n_ims=8)
print("\n" + "=" * 60)
print("VISUALIZANDO SUBSET DE VALIDACIÓN")
print("=" * 60)
visualize_subset(val_dl.dataset, n_ims=4)
# Opción C: Visualizar un batch del dataloader
print("\n" + "=" * 60)
print("VISUALIZANDO BATCH DEL DATALOADER DE ENTRENAMIENTO")
print("=" * 60)
visualize_dataloader(tr_dl, n_batches=1)
# ---------------------------------------------------------
# Función específica para tu caso actual
# ---------------------------------------------------------
def visualize_current():
"""
Función específica para visualizar con tu configuración actual
"""
print("=" * 70)
print("VISUALIZACIÓN DE DATOS - CONFIGURACIÓN ACTUAL")
print("=" * 70)
print(f"Número de clases: {n_cls}")
print(f"Device: {device}")
print(f"Batch size train: {tr_dl.batch_size}")
print(f"Batch size val: {val_dl.batch_size}")
print(f"Batch size test: {test_dl.batch_size}")
# Verificar acceso a ignore_index
if hasattr(tr_dl.dataset.dataset, 'ignore_index'):
ignore_idx = tr_dl.dataset.dataset.ignore_index
print(f"Ignore index: {ignore_idx}")
else:
print("Ignore index: 255 (default)")
ignore_idx = 255
# Visualizar algunas muestras de entrenamiento
import math
n_samples = 6
cols = 4
rows = math.ceil(n_samples * 2 / cols)
fig, axs = plt.subplots(rows, cols, figsize=(20, rows * 4))
axs = axs.flatten()
indices = random.sample(range(len(tr_dl.dataset)), n_samples)
i = 0
for plot_idx, subset_idx in enumerate(indices):
im, gt = tr_dl.dataset[subset_idx]
rgb = to_numpy_image(im.float())
gt_img = mask_to_rgb(gt, n_cls, ignore_idx)
# Obtener clases presentes en la máscara
if torch.is_tensor(gt):
unique_vals = torch.unique(gt).cpu().numpy()
else:
unique_vals = np.unique(gt)
valid_classes = [int(v) for v in unique_vals if v != ignore_idx and v < n_cls]
plot(axs[i], rgb, f"Train Img {plot_idx+1}")
i += 1
plot(axs[i], gt_img, f"Mask {plot_idx+1} (cls: {valid_classes})")
i += 1
if i >= len(axs):
break
for j in range(i, len(axs)):
axs[j].axis('off')
plt.suptitle(f'Dataset de Entrenamiento - {n_cls} clases (ignore={ignore_idx})', fontsize=16)
plt.tight_layout()
plt.show()
# Mostrar leyenda de colores
print("\n" + "=" * 60)
print("LEGENDA DE COLORES PARA LAS MÁSCARAS")
print("=" * 60)
for cls_name, color_name, cls_idx in CLASS_LEGEND:
print(f" Clase {cls_idx:2d}: {cls_name:12s} → {color_name}")
print(f" Ignore (255): gris oscuro")
# Ejecutar visualización
visualize_current()
============================================================ VISUALIZANDO SUBSET DE ENTRENAMIENTO ============================================================
============================================================ VISUALIZANDO SUBSET DE VALIDACIÓN ============================================================
============================================================ VISUALIZANDO BATCH DEL DATALOADER DE ENTRENAMIENTO ============================================================
Batch 0:
Images shape: torch.Size([4, 3, 256, 256])
Masks shape: torch.Size([4, 256, 256])
Unique mask values: [0, 1, 2, 3, 4, 5, 255]
clase 0: 197169 píxeles
clase 1: 35344 píxeles
clase 2: 15007 píxeles
clase 3: 3175 píxeles
clase 4: 896 píxeles
clase 5: 6648 píxeles
ignore (255): 3905 píxeles
======================================================================
VISUALIZACIÓN DE DATOS - CONFIGURACIÓN ACTUAL
======================================================================
Número de clases: 6
Device: cpu
Batch size train: 4
Batch size val: 4
Batch size test: 1
Ignore index: 255
============================================================ LEGENDA DE COLORES PARA LAS MÁSCARAS ============================================================ Clase 0: background → negro Ignore (255): gris oscuro Clase 1: topwear → rojo Ignore (255): gris oscuro Clase 2: lowerwear → azul Ignore (255): gris oscuro Clase 3: dress → naranja Ignore (255): gris oscuro Clase 4: footwear → violeta Ignore (255): gris oscuro Clase 5: body → verde Ignore (255): gris oscuro
Setup de Entrenamiento¶
In [187]:
class OptimizedSegmentationModel(nn.Module):
"""
Modelo optimizado para CPU con DeepLabV3Plus
"""
def __init__(self, n_cls=6, encoder_name="resnet34",encoder_weights="imagenet", dropout_rate=0.3):
super().__init__()
self.model = smp.DeepLabV3Plus(
encoder_name=encoder_name,
encoder_weights=encoder_weights, # Usar pesos preentrenados
in_channels=3,
classes=n_cls,
activation=None,
encoder_dropout=dropout_rate, # Dropout en encoder
decoder_dropout=dropout_rate, # Dropout en decoder
)
self.output_dropout = nn.Dropout2d(p=dropout_rate * 0.5)
# BatchNorm extra después del modelo
print(f"Modelo creado: DeepLabV3Plus con {encoder_name}")
print(f"Número de parámetros: {self.count_parameters():,}")
print(f"Clases: {n_cls}")
print(f"Modelo con dropout={dropout_rate}")
def forward(self, x):
x = self.model(x)
return x
def count_parameters(self):
return sum(p.numel() for p in self.parameters() if p.requires_grad)
# Crear el modelo
n_cls = 6 # Deberías obtener esto de tu dataset
model = OptimizedSegmentationModel(n_cls=n_cls, encoder_name="resnet34")
# Mover a CPU
device = "cpu"
model.to(device)
print(f"Modelo en dispositivo: {device}")
class Metrics():
def __init__(self, pred, gt, loss_fn, n_cls=6, ignore_index=255, eps=1e-8):
self.pred_logits = pred
self.pred = torch.argmax(pred, dim=1) # (batch, H, W)
# Asegurar que gt tenga la forma correcta
if gt.dim() == 4 and gt.size(1) == 1:
self.gt = gt.squeeze(1).long()
elif gt.dim() == 4 and gt.size(1) > 1:
# Si es one-hot, convertimos
self.gt = torch.argmax(gt, dim=1).long()
else:
self.gt = gt.long()
self.loss_fn = loss_fn
self.n_cls = n_cls
self.ignore_index = ignore_index
self.eps = eps
# Mover todo a CPU para cálculos de métricas
if self.pred_logits.is_cuda:
self.pred_logits = self.pred_logits.cpu()
self.pred = self.pred.cpu()
self.gt = self.gt.cpu()
def IoU_per_class_detailed(self):
"""IoU por clase con estadísticas detalladas"""
with torch.no_grad():
valid_mask = self.gt != self.ignore_index
if valid_mask.sum().item() == 0:
return {i: {"iou": 0.0, "pixels": 0} for i in range(self.n_cls)}
pred_valid = self.pred[valid_mask]
gt_valid = self.gt[valid_mask]
results = {}
for cls in range(self.n_cls):
pred_cls = pred_valid == cls
gt_cls = gt_valid == cls
intersection = (pred_cls & gt_cls).sum().float().item()
union = (pred_cls | gt_cls).sum().float().item()
total_pixels_cls = gt_cls.sum().float().item()
if union > 0:
iou = (intersection + self.eps) / (union + self.eps)
else:
iou = 0.0
# Precisión por clase
if pred_cls.sum() > 0:
precision = intersection / pred_cls.sum().float().item()
else:
precision = 0.0
# Recall por clase
if total_pixels_cls > 0:
recall = intersection / total_pixels_cls
else:
recall = 0.0
results[cls] = {
"iou": iou,
"precision": precision,
"recall": recall,
"pixels": total_pixels_cls,
"predicted_pixels": pred_cls.sum().float().item()
}
return results
def PA(self):
"""Pixel Accuracy (Precisión por píxel)"""
with torch.no_grad():
# Filtrar píxeles ignorados
valid_mask = self.gt != self.ignore_index
if valid_mask.sum().item() == 0:
return 0.0
correct = (self.pred == self.gt) & valid_mask
accuracy = correct.sum().float() / valid_mask.sum().float()
return accuracy.item()
def mIoU(self):
"""Mean Intersection over Union"""
with torch.no_grad():
# Filtrar píxeles ignorados
valid_mask = self.gt != self.ignore_index
if valid_mask.sum().item() == 0:
return 0.0
pred_valid = self.pred[valid_mask]
gt_valid = self.gt[valid_mask]
ious = []
for cls in range(self.n_cls):
pred_cls = pred_valid == cls
gt_cls = gt_valid == cls
intersection = (pred_cls & gt_cls).sum().float().item()
union = (pred_cls | gt_cls).sum().float().item()
if union > 0:
iou = (intersection + self.eps) / (union + self.eps)
ious.append(iou)
else:
# Si no hay píxeles de esta clase, omitimos
continue
if len(ious) == 0:
return 0.0
miou = sum(ious) / len(ious)
return miou
def IoU_per_class(self):
"""IoU por clase"""
with torch.no_grad():
valid_mask = self.gt != self.ignore_index
if valid_mask.sum().item() == 0:
return {f"class_{i}": 0.0 for i in range(self.n_cls)}
pred_valid = self.pred[valid_mask]
gt_valid = self.gt[valid_mask]
ious = {}
for cls in range(self.n_cls):
pred_cls = pred_valid == cls
gt_cls = gt_valid == cls
intersection = (pred_cls & gt_cls).sum().float().item()
union = (pred_cls | gt_cls).sum().float().item()
if union > 0:
iou = (intersection + self.eps) / (union + self.eps)
ious[f"class_{cls}"] = iou
else:
ious[f"class_{cls}"] = 0.0
return ious
Modelo creado: DeepLabV3Plus con resnet34 Número de parámetros: 22,438,742 Clases: 6 Modelo con dropout=0.3 Modelo en dispositivo: cpu
In [188]:
def calculate_class_weights(dataset, n_cls=6, ignore_index=255):
pixel_counts = np.zeros(n_cls, dtype=np.int64)
total_pixels = 0
for i in range(len(dataset)):
_, mask = dataset[i]
if torch.is_tensor(mask):
mask = mask.numpy()
valid = mask != ignore_index
total_pixels += valid.sum()
for cls in range(n_cls):
pixel_counts[cls] += np.sum(mask[valid] == cls)
class_freq = pixel_counts / (total_pixels + 1e-6)
class_weights = 1.0 / (class_freq + 1e-6)
class_weights = class_weights / class_weights.sum() * n_cls
class_weights = np.clip(class_weights, 0.5, 5.0)
print("Distribución de clases:", class_freq)
print("Pesos calculados:", class_weights)
return torch.tensor(class_weights, dtype=torch.float32)
In [189]:
# Calcular pesos de clase desde el dataset (tr_dl puede ser un DataLoader)
dataset_for_weights = tr_dl.dataset if isinstance(tr_dl, DataLoader) else tr_dl
class_weights = calculate_class_weights(dataset_for_weights, n_cls=n_cls, ignore_index=255)
# Mover a dispositivo si es un tensor
if isinstance(class_weights, torch.Tensor):
class_weights = class_weights.to(device)
print("Class weights:", class_weights)
Distribución de clases: [0.7524836 0.10086926 0.0586283 0.03802228 0.00668313 0.04331343] Pesos calculados: [0.5 0.5 0.5 0.69424743 3.94928803 0.60944051] Class weights: tensor([0.5000, 0.5000, 0.5000, 0.6942, 3.9493, 0.6094])
In [190]:
class DiceLoss(nn.Module):
def __init__(
self,
mode="multiclass",
classes=None,
log_loss=False,
smooth=1e-6,
ignore_index=255
):
super().__init__()
assert mode == "multiclass", "Esta implementación es solo para multiclase"
self.classes = classes
self.log_loss = log_loss
self.smooth = smooth
self.ignore_index = ignore_index
def forward(self, logits, target):
"""
logits: (B, C, H, W)
target: (B, H, W)
"""
num_classes = logits.shape[1]
# Máscara válida
valid_mask = target != self.ignore_index # (B, H, W)
# Reemplazar ignore_index por una clase válida dummy (0)
target_safe = target.clone()
target_safe[target_safe == self.ignore_index] = 0
# Softmax
probs = F.softmax(logits, dim=1)
# One-hot SEGURO
target_one_hot = F.one_hot(
target_safe, num_classes=num_classes
).permute(0, 3, 1, 2).float()
# Aplicar máscara
valid_mask = valid_mask.unsqueeze(1)
probs = probs * valid_mask
target_one_hot = target_one_hot * valid_mask
# Dice
dims = (0, 2, 3)
intersection = torch.sum(probs * target_one_hot, dims)
cardinality = torch.sum(probs + target_one_hot, dims)
dice = (2.0 * intersection + self.smooth) / (cardinality + self.smooth)
if self.classes is not None:
dice = dice[self.classes]
loss = 1.0 - dice
return loss.mean()
In [191]:
class FocalLoss(nn.Module):
def __init__(
self,
gamma=2.0,
weight=None,
ignore_index=255,
reduction="mean"
):
super().__init__()
self.gamma = gamma
self.ignore_index = ignore_index
self.reduction = reduction
self.ce = nn.CrossEntropyLoss(
weight=weight,
ignore_index=ignore_index,
reduction="none"
)
def forward(self, logits, target):
"""
logits: (B, C, H, W)
target: (B, H, W)
"""
ce_loss = self.ce(logits, target) # (B, H, W)
# pt = probabilidad del target correcto
pt = torch.exp(-ce_loss)
focal_loss = ((1 - pt) ** self.gamma) * ce_loss
if self.reduction == "mean":
return focal_loss.mean()
elif self.reduction == "sum":
return focal_loss.sum()
else:
return focal_loss
In [192]:
class CombinedLoss(nn.Module):
def __init__(self, class_weights, n_cls=6, ignore_index = 255):
super().__init__()
self.ce_loss = nn.CrossEntropyLoss(
weight=class_weights,
ignore_index=ignore_index
)
self.dice_loss = DiceLoss(
mode="multiclass",
classes=list(range(n_cls)),
log_loss=False,
ignore_index=ignore_index
)
self.focal_loss = FocalLoss(
gamma=2.0,
weight=class_weights,
ignore_index=ignore_index
)
self.weights = [0.4, 0.3, 0.3]
def forward(self, pred, target):
ce = self.ce_loss(pred, target)
dice = self.dice_loss(pred, target)
focal = self.focal_loss(pred, target)
return (
self.weights[0] * ce +
self.weights[1] * dice +
self.weights[2] * focal
)
In [193]:
def get_optimizer_and_scheduler(model, lr=3e-4):
# Optimizador con warmup
optimizer = torch.optim.AdamW(
model.parameters(),
lr=lr,
weight_decay=1e-4, # Regularización L2
betas=(0.9, 0.999)
)
# Scheduler con warmup y cosine annealing
scheduler = torch.optim.lr_scheduler.OneCycleLR(
optimizer,
max_lr=lr,
epochs=80,
steps_per_epoch=len(tr_dl),
pct_start=0.1, # 10% warmup
anneal_strategy='cos'
)
return optimizer, scheduler
Entrenamiento y validacion¶
In [194]:
class CPUTrainer:
"""
Trainer optimizado para entrenamiento en CPU
"""
def __init__(self, model, train_loader, val_loader,
criterion, optimizer, scheduler=None,
device="cpu", n_cls=6, ignore_index=255,patience=10,delta=0.001,min_epochs=20):
self.model = model
self.train_loader = train_loader
self.val_loader = val_loader
self.criterion = criterion
self.optimizer = optimizer
self.scheduler = scheduler
self.device = device
self.n_cls = n_cls
self.ignore_index = ignore_index
# Parámetros para Early Stopping
self.patience = patience # Número de épocas sin mejora para detener
self.delta = delta # Cambio mínimo para considerar mejora
self.min_epochs = min_epochs
self.counter = 0 # Contador de épocas sin mejora
self.best_score = None
self.best_state = None
self.early_stop = False
# Historial
self.history = {
'train_loss': [],
'val_loss': [],
'train_pa': [],
'val_pa': [],
'train_miou': [],
'val_miou': [],
'lr': [],
'per_class_iou': []
}
def _early_stopping(self, val_miou,val_loss, epoch):
"""Early stopping mejorado"""
# No considerar early stopping antes de min_epochs
if epoch < self.min_epochs:
return False
if self.best_score is None:
self.best_score = val_miou
# Guardar estado del modelo
self.best_state = {
'model_state': self.model.state_dict(),
'optimizer_state': self.optimizer.state_dict(),
'epoch': epoch,
'score': val_miou,
'val_loss_min': val_loss
}
return False
elif val_miou < self.best_score + self.delta:
self.counter += 1
print(f" EarlyStopping: {self.counter}/{self.patience} sin mejora")
if self.counter >= self.patience:
self.early_stop = True
# Restaurar mejor modelo
if self.best_state:
self.model.load_state_dict(self.best_state['model_state'])
self.optimizer.load_state_dict(self.best_state['optimizer_state'])
return True
else:
print(f" ✓ Mejora significativa: {val_miou:.4f} > {self.best_score:.4f}")
self.best_score = val_miou
self.counter = 0
# Actualizar mejor estado
self.best_state = {
'model_state': self.model.state_dict(),
'optimizer_state': self.optimizer.state_dict(),
'epoch': epoch,
'score': val_miou
}
return False
def train_epoch(self):
"""Entrena una época"""
self.model.train()
total_loss = 0.0
total_pa = 0.0
total_miou = 0.0
num_batches = 0
for batch_idx, (images, masks) in enumerate(self.train_loader):
# Mover a dispositivo
images = images.to(self.device).float()
masks = masks.to(self.device).long()
# Forward pass
self.optimizer.zero_grad()
outputs = self.model(images)
# Calcular pérdida
loss = self.criterion(outputs, masks)
# Backward pass
loss.backward()
torch.nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=1.0)
self.optimizer.step()
self.scheduler.step() # AQUÍ
# Calcular métricas
with torch.no_grad():
metrics = Metrics(outputs, masks, self.criterion,
n_cls=self.n_cls,
ignore_index=self.ignore_index)
pa = metrics.PA()
miou = metrics.mIoU()
total_loss += loss.item()
total_pa += pa
total_miou += miou
num_batches += 1
# Log cada cierto número de batches
if (batch_idx + 1) % 10 == 0:
print(f" Batch {batch_idx+1}/{len(self.train_loader)}: "
f"Loss: {loss.item():.4f}, PA: {pa:.4f}, mIoU: {miou:.4f}")
return {
'loss': total_loss / max(num_batches,1),
'pa': total_pa / max(num_batches,1),
'miou': total_miou / max(num_batches,1)
}
def validate(self):
"""Validación"""
self.model.eval()
total_loss = 0.0
total_pa = 0.0
total_miou = 0.0
num_batches = 0
with torch.no_grad():
for images, masks in self.val_loader:
images = images.to(self.device).float()
masks = masks.to(self.device).long()
outputs = self.model(images)
loss = self.criterion(outputs, masks)
metrics = Metrics(outputs, masks, self.criterion,
n_cls=self.n_cls,
ignore_index=self.ignore_index)
pa = metrics.PA()
miou = metrics.mIoU()
total_loss += loss.item()
total_pa += pa
total_miou += miou
num_batches += 1
return {
'loss': total_loss / max(num_batches,1),
'pa': total_pa / max(num_batches,1),
'miou': total_miou / max(num_batches,1)
}
def compute_epoch_iou(self):
intersection = torch.zeros(self.n_cls, device=self.device)
union = torch.zeros(self.n_cls, device=self.device)
with torch.no_grad():
for images, masks in self.val_loader:
images = images.to(self.device)
masks = masks.to(self.device)
outputs = self.model(images)
preds = torch.argmax(outputs, dim=1)
valid = masks != self.ignore_index
for cls in range(self.n_cls):
pred_cls = (preds == cls) & valid
gt_cls = (masks == cls) & valid
intersection[cls] += (pred_cls & gt_cls).sum()
union[cls] += (pred_cls | gt_cls).sum()
return {
f"class_{i}": (intersection[i] / (union[i] + 1e-6)).item()
for i in range(self.n_cls)
}
def train(self, num_epochs, save_path="best_model_mejorado.pth"):
"""Entrenamiento completo"""
best_miou = 0.0
print("\n" + "="*60)
print("INICIANDO ENTRENAMIENTO EN CPU")
print("="*60)
print(f"Early Stopping configurado: paciencia={self.patience}, delta={self.delta}")
for epoch in range(num_epochs):
start_time = time.time()
print(f"\nEpoch {epoch+1}/{num_epochs}")
print("-"*40)
# Entrenar
train_metrics = self.train_epoch()
# Validar
val_metrics = self.validate()
# Calcular métricas por clase
with torch.no_grad():
# Tomar un batch de validación
for images, masks in self.val_loader:
images = images.to(self.device)
masks = masks.to(self.device)
outputs = self.model(images)
metrics = Metrics(outputs, masks, self.criterion,
n_cls=self.n_cls,
ignore_index=self.ignore_index)
per_class_iou = metrics.IoU_per_class_detailed()
# Guardar en historial
self.history['train_loss'].append(train_metrics['loss'])
self.history['val_loss'].append(val_metrics['loss'])
self.history['train_pa'].append(train_metrics['pa'])
self.history['val_pa'].append(val_metrics['pa'])
self.history['train_miou'].append(train_metrics['miou'])
self.history['val_miou'].append(val_metrics['miou'])
self.history['lr'].append(self.optimizer.param_groups[0]['lr'])
self.history['per_class_iou'].append(per_class_iou)
# Tiempo de la época
epoch_time = time.time() - start_time
# Mostrar resultados
print(f"\nResumen Epoch {epoch+1}:")
print(f" Tiempo: {epoch_time:.2f}s")
print(f" Train Loss: {train_metrics['loss']:.4f} | "
f"PA: {train_metrics['pa']:.4f} | "
f"mIoU: {train_metrics['miou']:.4f}")
print(f" Val Loss: {val_metrics['loss']:.4f} | "
f"PA: {val_metrics['pa']:.4f} | "
f"mIoU: {val_metrics['miou']:.4f}")
print(f" Learning Rate: {self.optimizer.param_groups[0]['lr']:.6f}")
# Guardar mejor modelo
if val_metrics['miou'] > best_miou:
best_miou = val_metrics['miou']
torch.save({
'epoch': epoch,
'model_state_dict': self.model.state_dict(),
'optimizer_state_dict': self.optimizer.state_dict(),
'val_miou': best_miou,
'history': self.history,
}, save_path)
print(f" ✓ Modelo guardado (mIoU: {best_miou:.4f})")
# Verificar Early Stopping (pasando el número de época)
if self._early_stopping(val_metrics['miou'], val_metrics['loss'], epoch):
print(f"\n{'='*60}")
print("EARLY STOPPING ACTIVADO")
print(f"Sin mejora significativa por {self.patience} épocas")
print(f"Mejor mIoU alcanzado: {best_miou:.4f}")
print(f"Entrenamiento detenido en época {epoch+1}")
print('='*60)
break
# print("\n" + "="*60)
# print("ENTRENAMIENTO COMPLETADO")
# print(f"Mejor mIoU: {best_miou:.4f}")
# print("="*60)
if not self.early_stop:
print("\n" + "="*60)
print("ENTRENAMIENTO COMPLETADO (sin early stopping)")
print(f"Mejor mIoU: {best_miou:.4f}")
print("="*60)
return self.history
In [195]:
def plot_class_metrics(history, class_names):
"""Visualiza métricas por clase a través del tiempo"""
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# Extraer IoU por clase por época
epochs = range(len(history['per_class_iou']))
for cls, cls_name in enumerate(class_names):
row = cls // 3
col = cls % 3
iou_values = []
for epoch_iou in history['per_class_iou']:
if cls in epoch_iou:
iou_values.append(epoch_iou[cls]['iou'])
else:
iou_values.append(0)
axes[row, col].plot(epochs, iou_values, 'b-', linewidth=2)
axes[row, col].set_title(f'{cls_name} (Clase {cls})')
axes[row, col].set_xlabel('Época')
axes[row, col].set_ylabel('IoU')
axes[row, col].grid(True, alpha=0.3)
# Añadir mejor IoU
best_iou = max(iou_values) if iou_values else 0
axes[row, col].axhline(y=best_iou, color='r', linestyle='--', alpha=0.5)
axes[row, col].text(0.5, 0.95, f'Mejor: {best_iou:.3f}',
transform=axes[row, col].transAxes,
ha='center', va='top',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
plt.suptitle('Evolución del IoU por Clase', fontsize=16)
plt.tight_layout()
plt.show()
In [196]:
# FUNCIÓN DE ENTRENAMIENTO
# ============================================
def entrenamiento(tr_dl, val_dl, n_cls=6, class_names=None):
"""
Inicia el entrenamiento del modelo
Args:
tr_dl: DataLoader de entrenamiento
val_dl: DataLoader de validación
n_cls: Número de clases (debería ser 8 según tu mapeo)
"""
# Configuración
device = "cpu"
ignore_index = 255
num_epochs = 80 # a 100 Reducido para prueba, puedes aumentarlo
learning_rate = 3e-4 #3e-4
dropout_rate = 0.3
# Parámetros para Early Stopping
patience = 15 # Número de épocas sin mejora para detener
delta = 0.001 # Mejora mínima requerida
min_epochs = 15
print("="*60)
print("CONFIGURACIÓN DEL ENTRENAMIENTO")
print("="*60)
print(f"Dispositivo: {device}")
print(f"Número de clases: {n_cls}")
print(f"Índice ignore: {ignore_index}")
print(f"Épocas: {num_epochs}")
print(f"Early stopping: paciencia={patience}, delta={delta}")
print(f"Learning rate: {learning_rate}")
print(f"Tamaño batch entrenamiento: {tr_dl.batch_size}")
print(f"Tamaño batch validación: {val_dl.batch_size}")
print(f" Dropout: {dropout_rate}")
print("\nCalculando pesos de clase...")
# 1. Crear modelo - USAR RESNET18 EN LUGAR DE RESNET32
print("\nCreando modelo...")
model = OptimizedSegmentationModel(
n_cls=n_cls,
encoder_name="resnet34",
encoder_weights="imagenet",
dropout_rate= dropout_rate
).to(device)
class_weights = calculate_class_weights(tr_dl.dataset, n_cls, ignore_index).to(device)
criterion = CombinedLoss(
n_cls=n_cls,
ignore_index=ignore_index,
class_weights = class_weights,
)
# 4. Optimizador y OneCycleLR
optimizer = torch.optim.AdamW(
model.parameters(),
lr=learning_rate,
weight_decay=1e-4
)
scheduler = torch.optim.lr_scheduler.OneCycleLR(
optimizer,
max_lr=learning_rate,
epochs=num_epochs,
steps_per_epoch=len(tr_dl),
pct_start=0.1,
anneal_strategy='cos'
)
# Crear trainer
print("\nCreando trainer...")
trainer = CPUTrainer(
model=model,
train_loader=tr_dl,
val_loader=val_dl,
criterion=criterion,
optimizer=optimizer,
scheduler=scheduler,
device=device,
n_cls=n_cls,
ignore_index=ignore_index,
patience=patience,
delta=delta,
min_epochs=min_epochs
)
# 6. Entrenar
print("\nIniciando entrenamiento...")
history = trainer.train(num_epochs=num_epochs, save_path="best_model_mejorado.pth")
if class_names:
plot_class_metrics(history, class_names)
return model, history
In [197]:
def verificar_dataloaders(tr_dl, val_dl):
"""Verifica que los DataLoaders tengan los tipos y clases correctas"""
print("=" * 60)
print("VERIFICACIÓN DE DATALOADERS")
print("=" * 60)
# Mapeo id → nombre
class_id_to_name = {
0: "background",
1: "topwear",
2: "lowerwear",
3: "dress",
4: "footwear",
5: "body",
255: "ignore"
}
# -------------------------
# Batch de entrenamiento
# -------------------------
images, masks = next(iter(tr_dl))
print("\nBatch de entrenamiento:")
print(f" Images dtype: {images.dtype}, shape: {images.shape}")
print(f" Masks dtype: {masks.dtype}, shape: {masks.shape}")
print(f" Images range: [{images.min():.3f}, {images.max():.3f}]")
print(f" Masks unique values: {torch.unique(masks).tolist()}")
# Verificar tipo de máscara
if masks.dtype != torch.int64:
print(f"\n ADVERTENCIA: Máscaras son {masks.dtype}, deberían ser torch.int64 (Long)")
print(" Convirtiendo a Long...")
masks = masks.long()
print(f" Nuevo dtype: {masks.dtype}")
# -------------------------
# Batch de validación
# -------------------------
images_val, masks_val = next(iter(val_dl))
print("\nBatch de validación:")
print(f" Images dtype: {images_val.dtype}, shape: {images_val.shape}")
print(f" Masks dtype: {masks_val.dtype}, shape: {masks_val.shape}")
# -------------------------
# Ignore index
# -------------------------
ignore_count_train = (masks == 255).sum().item()
ignore_count_val = (masks_val == 255).sum().item()
print("\nPíxeles ignorados (255):")
print(f" Train: {ignore_count_train}")
print(f" Val: {ignore_count_val}")
# -------------------------
# Clases presentes (train)
# -------------------------
print("\nClases presentes en batch de entrenamiento:")
unique_classes = torch.unique(masks)
for cls in unique_classes:
cls_id = int(cls.item())
pixel_count = (masks == cls).sum().item()
cls_name = class_id_to_name.get(cls_id, "UNKNOWN")
print(f" Clase {cls_id:>3} ({cls_name:<10}) → {pixel_count} píxeles")
return True
# Paso 1: Verificar DataLoaders
print("Paso 1: Verificando DataLoaders...")
verificar_dataloaders(tr_dl, val_dl)
# Paso 2: Crear función de conversión de tipos si es necesario
def fix_dataloader_types(dataloader):
"""Función generadora que convierte máscaras a Long"""
for images, masks in dataloader:
yield images, masks.long()
def verificar_varios_batches(dataloader, n_batches=10):
class_counts = {}
for i, (_, masks) in enumerate(dataloader):
if i >= n_batches:
break
for cls in torch.unique(masks):
cls = int(cls.item())
class_counts[cls] = class_counts.get(cls, 0) + 1
print("\nClases vistas en", n_batches, "batches:")
for cls, count in sorted(class_counts.items()):
print(f" Clase {cls}: aparece en {count} batches")
Paso 1: Verificando DataLoaders... ============================================================ VERIFICACIÓN DE DATALOADERS ============================================================ Batch de entrenamiento: Images dtype: torch.float32, shape: torch.Size([4, 3, 256, 256]) Masks dtype: torch.int64, shape: torch.Size([4, 256, 256]) Images range: [-2.118, 2.640] Masks unique values: [0, 1, 2, 3, 4, 5, 255] Batch de validación: Images dtype: torch.float32, shape: torch.Size([4, 3, 256, 256]) Masks dtype: torch.int64, shape: torch.Size([4, 256, 256]) Píxeles ignorados (255): Train: 4075 Val: 6595 Clases presentes en batch de entrenamiento: Clase 0 (background) → 192303 píxeles Clase 1 (topwear ) → 29850 píxeles Clase 2 (lowerwear ) → 9351 píxeles Clase 3 (dress ) → 11511 píxeles Clase 4 (footwear ) → 931 píxeles Clase 5 (body ) → 14123 píxeles Clase 255 (ignore ) → 4075 píxeles
In [198]:
# FUNCIÓN PARA VISUALIZAR RESULTADOS
# ============================================
def plot_training_history(history):
"""Visualiza el historial de entrenamiento"""
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# Pérdida
axes[0, 0].plot(history['train_loss'], label='Train')
axes[0, 0].plot(history['val_loss'], label='Val')
axes[0, 0].set_title('Loss')
axes[0, 0].set_xlabel('Epoch')
axes[0, 0].set_ylabel('Loss')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# Pixel Accuracy
axes[0, 1].plot(history['train_pa'], label='Train')
axes[0, 1].plot(history['val_pa'], label='Val')
axes[0, 1].set_title('Pixel Accuracy')
axes[0, 1].set_xlabel('Epoch')
axes[0, 1].set_ylabel('PA')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# mIoU
axes[0, 2].plot(history['train_miou'], label='Train')
axes[0, 2].plot(history['val_miou'], label='Val')
axes[0, 2].set_title('Mean IoU')
axes[0, 2].set_xlabel('Epoch')
axes[0, 2].set_ylabel('mIoU')
axes[0, 2].legend()
axes[0, 2].grid(True, alpha=0.3)
# Learning Rate
axes[1, 0].plot(history['lr'])
axes[1, 0].set_title('Learning Rate')
axes[1, 0].set_xlabel('Epoch')
axes[1, 0].set_ylabel('LR')
axes[1, 0].grid(True, alpha=0.3)
# Comparación Train vs Val
axes[1, 1].plot(history['train_loss'], label='Train Loss', alpha=0.7)
axes[1, 1].plot(history['val_loss'], label='Val Loss', alpha=0.7)
axes[1, 1].plot(history['train_miou'], label='Train mIoU', alpha=0.7)
axes[1, 1].plot(history['val_miou'], label='Val mIoU', alpha=0.7)
axes[1, 1].set_title('Comparación Train vs Val')
axes[1, 1].set_xlabel('Epoch')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
# Mejor época (basado en val_miou)
best_epoch = np.argmax(history['val_miou'])
axes[1, 2].text(0.1, 0.5,
f"Mejor época: {best_epoch + 1}\n"
f"Mejor mIoU: {history['val_miou'][best_epoch]:.4f}\n"
f"Mejor PA: {history['val_pa'][best_epoch]:.4f}\n"
f"Loss en mejor época: {history['val_loss'][best_epoch]:.4f}",
fontsize=12,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue"))
axes[1, 2].axis('off')
plt.suptitle('Historial de Entrenamiento', fontsize=16)
plt.tight_layout()
plt.show()
# ============================================
# EJECUTAR ENTRENAMIENTO
# ============================================
print("Verificando configuración...")
print(f"tr_dl definido: {'tr_dl' in locals() or 'tr_dl' in globals()}")
print(f"val_dl definido: {'val_dl' in locals() or 'val_dl' in globals()}")
print(f"n_cls: {n_cls if 'n_cls' in locals() or 'n_cls' in globals() else 'No definido'}")
# Si todo está bien, ejecutar entrenamiento
if 'tr_dl' in locals() and 'val_dl' in locals():
try:
# Iniciar entrenamiento
model, history = entrenamiento(tr_dl, val_dl, n_cls=info['n_cls'],class_names=info['class_names'])
# Visualizar resultados
plot_training_history(history)
print("\n¡Entrenamiento completado exitosamente!")
print(f"Historial guardado. Mejor mIoU: {max(history['val_miou']):.4f}")
except Exception as e:
print(f"\nError durante el entrenamiento: {e}")
else:
print("\nError: tr_dl y/o val_dl no están definidos")
Verificando configuración... tr_dl definido: True val_dl definido: True n_cls: 6 ============================================================ CONFIGURACIÓN DEL ENTRENAMIENTO ============================================================ Dispositivo: cpu Número de clases: 6 Índice ignore: 255 Épocas: 80 Early stopping: paciencia=15, delta=0.001 Learning rate: 0.0003 Tamaño batch entrenamiento: 4 Tamaño batch validación: 4 Dropout: 0.3 Calculando pesos de clase... Creando modelo... Modelo creado: DeepLabV3Plus con resnet34 Número de parámetros: 22,438,742 Clases: 6 Modelo con dropout=0.3 Distribución de clases: [0.75137613 0.10135447 0.05910229 0.03842691 0.00647621 0.04326399] Pesos calculados: [0.5 0.5 0.5 0.67404747 3.99897941 0.5986881 ] Creando trainer... Iniciando entrenamiento... ============================================================ INICIANDO ENTRENAMIENTO EN CPU ============================================================ Early Stopping configurado: paciencia=15, delta=0.001 Epoch 1/80 ---------------------------------------- Batch 10/200: Loss: 1.1526, PA: 0.1242, mIoU: 0.0574 Batch 20/200: Loss: 1.1461, PA: 0.1633, mIoU: 0.0639 Batch 30/200: Loss: 1.1008, PA: 0.2276, mIoU: 0.0928 Batch 40/200: Loss: 1.0502, PA: 0.3238, mIoU: 0.1254 Batch 50/200: Loss: 1.0142, PA: 0.3959, mIoU: 0.1468 Batch 60/200: Loss: 1.0091, PA: 0.4610, mIoU: 0.1598 Batch 70/200: Loss: 0.9613, PA: 0.5551, mIoU: 0.2006 Batch 80/200: Loss: 0.9346, PA: 0.5870, mIoU: 0.2105 Batch 90/200: Loss: 0.8962, PA: 0.6403, mIoU: 0.2257 Batch 100/200: Loss: 0.9261, PA: 0.5973, mIoU: 0.2126 Batch 110/200: Loss: 0.8557, PA: 0.6883, mIoU: 0.2696 Batch 120/200: Loss: 0.8637, PA: 0.7070, mIoU: 0.2563 Batch 130/200: Loss: 0.8252, PA: 0.7101, mIoU: 0.2729 Batch 140/200: Loss: 0.7822, PA: 0.7426, mIoU: 0.2795 Batch 150/200: Loss: 0.7463, PA: 0.7733, mIoU: 0.3398 Batch 160/200: Loss: 0.7139, PA: 0.7865, mIoU: 0.3230 Batch 170/200: Loss: 0.7262, PA: 0.7558, mIoU: 0.3055 Batch 180/200: Loss: 0.7378, PA: 0.7380, mIoU: 0.2381 Batch 190/200: Loss: 0.6848, PA: 0.8033, mIoU: 0.3832 Batch 200/200: Loss: 0.6969, PA: 0.7470, mIoU: 0.2859 Resumen Epoch 1: Tiempo: 438.13s Train Loss: 0.8994 | PA: 0.5601 | mIoU: 0.2198 Val Loss: 0.5725 | PA: 0.8344 | mIoU: 0.4094 Learning Rate: 0.000023 ✓ Modelo guardado (mIoU: 0.4094) Epoch 2/80 ---------------------------------------- Batch 10/200: Loss: 0.6381, PA: 0.8099, mIoU: 0.4051 Batch 20/200: Loss: 0.5978, PA: 0.8134, mIoU: 0.4028 Batch 30/200: Loss: 0.5952, PA: 0.8227, mIoU: 0.3970 Batch 40/200: Loss: 0.5920, PA: 0.8094, mIoU: 0.3781 Batch 50/200: Loss: 0.5484, PA: 0.8392, mIoU: 0.3912 Batch 60/200: Loss: 0.5294, PA: 0.8464, mIoU: 0.4562 Batch 70/200: Loss: 0.5742, PA: 0.8155, mIoU: 0.3611 Batch 80/200: Loss: 0.4670, PA: 0.8816, mIoU: 0.5682 Batch 90/200: Loss: 0.5962, PA: 0.8353, mIoU: 0.3906 Batch 100/200: Loss: 0.5366, PA: 0.8087, mIoU: 0.3854 Batch 110/200: Loss: 0.4807, PA: 0.8511, mIoU: 0.4567 Batch 120/200: Loss: 0.5177, PA: 0.8363, mIoU: 0.3843 Batch 130/200: Loss: 0.4798, PA: 0.8484, mIoU: 0.3798 Batch 140/200: Loss: 0.5015, PA: 0.8330, mIoU: 0.4223 Batch 150/200: Loss: 0.5163, PA: 0.8098, mIoU: 0.3671 Batch 160/200: Loss: 0.4846, PA: 0.8198, mIoU: 0.3447 Batch 170/200: Loss: 0.4216, PA: 0.8795, mIoU: 0.4457 Batch 180/200: Loss: 0.4500, PA: 0.8512, mIoU: 0.4277 Batch 190/200: Loss: 0.4793, PA: 0.8264, mIoU: 0.3337 Batch 200/200: Loss: 0.4607, PA: 0.8195, mIoU: 0.3787 Resumen Epoch 2: Tiempo: 432.08s Train Loss: 0.5198 | PA: 0.8375 | mIoU: 0.4163 Val Loss: 0.3570 | PA: 0.8947 | mIoU: 0.5182 Learning Rate: 0.000054 ✓ Modelo guardado (mIoU: 0.5182) Epoch 3/80 ---------------------------------------- Batch 10/200: Loss: 0.3756, PA: 0.8835, mIoU: 0.5497 Batch 20/200: Loss: 0.3951, PA: 0.8740, mIoU: 0.4361 Batch 30/200: Loss: 0.4581, PA: 0.8359, mIoU: 0.4007 Batch 40/200: Loss: 0.3914, PA: 0.8629, mIoU: 0.4792 Batch 50/200: Loss: 0.3708, PA: 0.8655, mIoU: 0.5198 Batch 60/200: Loss: 0.3421, PA: 0.8865, mIoU: 0.5335 Batch 70/200: Loss: 0.3374, PA: 0.9049, mIoU: 0.5208 Batch 80/200: Loss: 0.3696, PA: 0.8689, mIoU: 0.4595 Batch 90/200: Loss: 0.4050, PA: 0.8583, mIoU: 0.4354 Batch 100/200: Loss: 0.3898, PA: 0.8571, mIoU: 0.4511 Batch 110/200: Loss: 0.3046, PA: 0.9286, mIoU: 0.5567 Batch 120/200: Loss: 0.3636, PA: 0.8855, mIoU: 0.5042 Batch 130/200: Loss: 0.3583, PA: 0.8882, mIoU: 0.4194 Batch 140/200: Loss: 0.2925, PA: 0.9058, mIoU: 0.5595 Batch 150/200: Loss: 0.3353, PA: 0.8682, mIoU: 0.5027 Batch 160/200: Loss: 0.2612, PA: 0.9315, mIoU: 0.5523 Batch 170/200: Loss: 0.3301, PA: 0.8886, mIoU: 0.4447 Batch 180/200: Loss: 0.3573, PA: 0.8538, mIoU: 0.4916 Batch 190/200: Loss: 0.3695, PA: 0.8589, mIoU: 0.4443 Batch 200/200: Loss: 0.3692, PA: 0.8514, mIoU: 0.3937 Resumen Epoch 3: Tiempo: 405.45s Train Loss: 0.3614 | PA: 0.8802 | mIoU: 0.4916 Val Loss: 0.2921 | PA: 0.9064 | mIoU: 0.5543 Learning Rate: 0.000101 ✓ Modelo guardado (mIoU: 0.5543) Epoch 4/80 ---------------------------------------- Batch 10/200: Loss: 0.3414, PA: 0.8706, mIoU: 0.4485 Batch 20/200: Loss: 0.4236, PA: 0.8432, mIoU: 0.4173 Batch 30/200: Loss: 0.3514, PA: 0.8736, mIoU: 0.3842 Batch 40/200: Loss: 0.2822, PA: 0.9074, mIoU: 0.5712 Batch 50/200: Loss: 0.2916, PA: 0.9033, mIoU: 0.5434 Batch 60/200: Loss: 0.2821, PA: 0.8981, mIoU: 0.5671 Batch 70/200: Loss: 0.2911, PA: 0.9038, mIoU: 0.5191 Batch 80/200: Loss: 0.3668, PA: 0.8514, mIoU: 0.4783 Batch 90/200: Loss: 0.2448, PA: 0.9253, mIoU: 0.6134 Batch 100/200: Loss: 0.3226, PA: 0.8848, mIoU: 0.5321 Batch 110/200: Loss: 0.2594, PA: 0.9188, mIoU: 0.5635 Batch 120/200: Loss: 0.2364, PA: 0.9169, mIoU: 0.6115 Batch 130/200: Loss: 0.2325, PA: 0.9145, mIoU: 0.6097 Batch 140/200: Loss: 0.3111, PA: 0.8747, mIoU: 0.4707 Batch 150/200: Loss: 0.3487, PA: 0.8562, mIoU: 0.4132 Batch 160/200: Loss: 0.3199, PA: 0.8664, mIoU: 0.4509 Batch 170/200: Loss: 0.2391, PA: 0.9041, mIoU: 0.5705 Batch 180/200: Loss: 0.2899, PA: 0.8771, mIoU: 0.4998 Batch 190/200: Loss: 0.3561, PA: 0.8613, mIoU: 0.4790 Batch 200/200: Loss: 0.3500, PA: 0.8733, mIoU: 0.4925 Resumen Epoch 4: Tiempo: 402.93s Train Loss: 0.2928 | PA: 0.8975 | mIoU: 0.5359 Val Loss: 0.2282 | PA: 0.9155 | mIoU: 0.5730 Learning Rate: 0.000156 ✓ Modelo guardado (mIoU: 0.5730) Epoch 5/80 ---------------------------------------- Batch 10/200: Loss: 0.3070, PA: 0.9007, mIoU: 0.4999 Batch 20/200: Loss: 0.2303, PA: 0.9208, mIoU: 0.5466 Batch 30/200: Loss: 0.2281, PA: 0.9152, mIoU: 0.6290 Batch 40/200: Loss: 0.1734, PA: 0.9511, mIoU: 0.7584 Batch 50/200: Loss: 0.2676, PA: 0.8924, mIoU: 0.5546 Batch 60/200: Loss: 0.3133, PA: 0.8845, mIoU: 0.5226 Batch 70/200: Loss: 0.2538, PA: 0.8864, mIoU: 0.5351 Batch 80/200: Loss: 0.3667, PA: 0.8861, mIoU: 0.4458 Batch 90/200: Loss: 0.1772, PA: 0.9400, mIoU: 0.7112 Batch 100/200: Loss: 0.2686, PA: 0.9100, mIoU: 0.6473 Batch 110/200: Loss: 0.2148, PA: 0.9177, mIoU: 0.6265 Batch 120/200: Loss: 0.2944, PA: 0.8837, mIoU: 0.4831 Batch 130/200: Loss: 0.2489, PA: 0.9186, mIoU: 0.5102 Batch 140/200: Loss: 0.2337, PA: 0.9288, mIoU: 0.5899 Batch 150/200: Loss: 0.3316, PA: 0.8492, mIoU: 0.4474 Batch 160/200: Loss: 0.2935, PA: 0.8989, mIoU: 0.5226 Batch 170/200: Loss: 0.2671, PA: 0.9059, mIoU: 0.5356 Batch 180/200: Loss: 0.2354, PA: 0.9074, mIoU: 0.5871 Batch 190/200: Loss: 0.2650, PA: 0.8917, mIoU: 0.5573 Batch 200/200: Loss: 0.1596, PA: 0.9487, mIoU: 0.6959 Resumen Epoch 5: Tiempo: 406.86s Train Loss: 0.2676 | PA: 0.9047 | mIoU: 0.5548 Val Loss: 0.2112 | PA: 0.9309 | mIoU: 0.6334 Learning Rate: 0.000211 ✓ Modelo guardado (mIoU: 0.6334) Epoch 6/80 ---------------------------------------- Batch 10/200: Loss: 0.2583, PA: 0.9229, mIoU: 0.5788 Batch 20/200: Loss: 0.2904, PA: 0.8830, mIoU: 0.5277 Batch 30/200: Loss: 0.2217, PA: 0.8974, mIoU: 0.5873 Batch 40/200: Loss: 0.2188, PA: 0.9112, mIoU: 0.5474 Batch 50/200: Loss: 0.2675, PA: 0.8817, mIoU: 0.5016 Batch 60/200: Loss: 0.3292, PA: 0.8696, mIoU: 0.5030 Batch 70/200: Loss: 0.2100, PA: 0.9193, mIoU: 0.6026 Batch 80/200: Loss: 0.2639, PA: 0.9050, mIoU: 0.5732 Batch 90/200: Loss: 0.2184, PA: 0.9334, mIoU: 0.5870 Batch 100/200: Loss: 0.3493, PA: 0.8755, mIoU: 0.5142 Batch 110/200: Loss: 0.2175, PA: 0.9183, mIoU: 0.5786 Batch 120/200: Loss: 0.2223, PA: 0.9300, mIoU: 0.6570 Batch 130/200: Loss: 0.1678, PA: 0.9428, mIoU: 0.7014 Batch 140/200: Loss: 0.1870, PA: 0.9329, mIoU: 0.6154 Batch 150/200: Loss: 0.2264, PA: 0.9096, mIoU: 0.6116 Batch 160/200: Loss: 0.2272, PA: 0.9117, mIoU: 0.5539 Batch 170/200: Loss: 0.1891, PA: 0.9297, mIoU: 0.6429 Batch 180/200: Loss: 0.2489, PA: 0.9084, mIoU: 0.5012 Batch 190/200: Loss: 0.2395, PA: 0.9132, mIoU: 0.5177 Batch 200/200: Loss: 0.2448, PA: 0.9037, mIoU: 0.5947 Resumen Epoch 6: Tiempo: 408.51s Train Loss: 0.2491 | PA: 0.9094 | mIoU: 0.5734 Val Loss: 0.2047 | PA: 0.9231 | mIoU: 0.6057 Learning Rate: 0.000258 Epoch 7/80 ---------------------------------------- Batch 10/200: Loss: 0.2349, PA: 0.9243, mIoU: 0.5205 Batch 20/200: Loss: 0.2734, PA: 0.9114, mIoU: 0.5478 Batch 30/200: Loss: 0.2666, PA: 0.9065, mIoU: 0.5168 Batch 40/200: Loss: 0.1446, PA: 0.9598, mIoU: 0.7379 Batch 50/200: Loss: 0.2683, PA: 0.9131, mIoU: 0.5523 Batch 60/200: Loss: 0.3615, PA: 0.8791, mIoU: 0.4693 Batch 70/200: Loss: 0.3184, PA: 0.8980, mIoU: 0.5127 Batch 80/200: Loss: 0.2904, PA: 0.9019, mIoU: 0.5263 Batch 90/200: Loss: 0.1832, PA: 0.9315, mIoU: 0.6382 Batch 100/200: Loss: 0.2488, PA: 0.9160, mIoU: 0.5189 Batch 110/200: Loss: 0.2272, PA: 0.9359, mIoU: 0.5125 Batch 120/200: Loss: 0.2460, PA: 0.9164, mIoU: 0.5350 Batch 130/200: Loss: 0.2406, PA: 0.9085, mIoU: 0.5141 Batch 140/200: Loss: 0.2262, PA: 0.9122, mIoU: 0.6182 Batch 150/200: Loss: 0.2284, PA: 0.9320, mIoU: 0.6635 Batch 160/200: Loss: 0.2170, PA: 0.9209, mIoU: 0.6129 Batch 170/200: Loss: 0.2940, PA: 0.8852, mIoU: 0.4458 Batch 180/200: Loss: 0.2173, PA: 0.9203, mIoU: 0.5702 Batch 190/200: Loss: 0.2030, PA: 0.9156, mIoU: 0.6378 Batch 200/200: Loss: 0.1821, PA: 0.9303, mIoU: 0.6059 Resumen Epoch 7: Tiempo: 404.05s Train Loss: 0.2407 | PA: 0.9128 | mIoU: 0.5810 Val Loss: 0.2079 | PA: 0.9329 | mIoU: 0.6224 Learning Rate: 0.000289 Epoch 8/80 ---------------------------------------- Batch 10/200: Loss: 0.1840, PA: 0.9382, mIoU: 0.6700 Batch 20/200: Loss: 0.4843, PA: 0.8845, mIoU: 0.4859 Batch 30/200: Loss: 0.3177, PA: 0.8859, mIoU: 0.4575 Batch 40/200: Loss: 0.2526, PA: 0.9140, mIoU: 0.5533 Batch 50/200: Loss: 0.1947, PA: 0.9406, mIoU: 0.6603 Batch 60/200: Loss: 0.2364, PA: 0.8897, mIoU: 0.5773 Batch 70/200: Loss: 0.2058, PA: 0.9268, mIoU: 0.6510 Batch 80/200: Loss: 0.1991, PA: 0.9176, mIoU: 0.6618 Batch 90/200: Loss: 0.3946, PA: 0.8530, mIoU: 0.3516 Batch 100/200: Loss: 0.2303, PA: 0.9160, mIoU: 0.5262 Batch 110/200: Loss: 0.2212, PA: 0.9131, mIoU: 0.6006 Batch 120/200: Loss: 0.1654, PA: 0.9567, mIoU: 0.7347 Batch 130/200: Loss: 0.3353, PA: 0.8771, mIoU: 0.4703 Batch 140/200: Loss: 0.2143, PA: 0.9287, mIoU: 0.5877 Batch 150/200: Loss: 0.2109, PA: 0.9209, mIoU: 0.5993 Batch 160/200: Loss: 0.2010, PA: 0.9327, mIoU: 0.7020 Batch 170/200: Loss: 0.2686, PA: 0.9189, mIoU: 0.5003 Batch 180/200: Loss: 0.1740, PA: 0.9449, mIoU: 0.6764 Batch 190/200: Loss: 0.2614, PA: 0.9287, mIoU: 0.5308 Batch 200/200: Loss: 0.3409, PA: 0.8579, mIoU: 0.4197 Resumen Epoch 8: Tiempo: 411.39s Train Loss: 0.2394 | PA: 0.9143 | mIoU: 0.5843 Val Loss: 0.2024 | PA: 0.9297 | mIoU: 0.6184 Learning Rate: 0.000300 Epoch 9/80 ---------------------------------------- Batch 10/200: Loss: 0.2581, PA: 0.8903, mIoU: 0.5768 Batch 20/200: Loss: 0.3206, PA: 0.8538, mIoU: 0.4839 Batch 30/200: Loss: 0.2411, PA: 0.9183, mIoU: 0.6854 Batch 40/200: Loss: 0.2191, PA: 0.8973, mIoU: 0.5384 Batch 50/200: Loss: 0.2001, PA: 0.9289, mIoU: 0.6669 Batch 60/200: Loss: 0.3257, PA: 0.8759, mIoU: 0.4385 Batch 70/200: Loss: 0.2104, PA: 0.9101, mIoU: 0.6437 Batch 80/200: Loss: 0.1509, PA: 0.9504, mIoU: 0.7243 Batch 90/200: Loss: 0.3110, PA: 0.8877, mIoU: 0.4532 Batch 100/200: Loss: 0.1969, PA: 0.9376, mIoU: 0.6727 Batch 110/200: Loss: 0.2246, PA: 0.9225, mIoU: 0.7711 Batch 120/200: Loss: 0.2282, PA: 0.9118, mIoU: 0.5699 Batch 130/200: Loss: 0.2414, PA: 0.9452, mIoU: 0.5559 Batch 140/200: Loss: 0.2127, PA: 0.9331, mIoU: 0.6371 Batch 150/200: Loss: 0.1769, PA: 0.9501, mIoU: 0.6967 Batch 160/200: Loss: 0.2842, PA: 0.8864, mIoU: 0.5143 Batch 170/200: Loss: 0.2251, PA: 0.9262, mIoU: 0.5603 Batch 180/200: Loss: 0.2025, PA: 0.9438, mIoU: 0.5464 Batch 190/200: Loss: 0.2128, PA: 0.9270, mIoU: 0.6181 Batch 200/200: Loss: 0.1709, PA: 0.9455, mIoU: 0.7726 Resumen Epoch 9: Tiempo: 406.68s Train Loss: 0.2316 | PA: 0.9173 | mIoU: 0.5926 Val Loss: 0.1863 | PA: 0.9387 | mIoU: 0.6520 Learning Rate: 0.000300 ✓ Modelo guardado (mIoU: 0.6520) Epoch 10/80 ---------------------------------------- Batch 10/200: Loss: 0.2577, PA: 0.9151, mIoU: 0.5493 Batch 20/200: Loss: 0.2248, PA: 0.9016, mIoU: 0.6062 Batch 30/200: Loss: 0.2230, PA: 0.9246, mIoU: 0.5437 Batch 40/200: Loss: 0.2035, PA: 0.9278, mIoU: 0.5839 Batch 50/200: Loss: 0.1956, PA: 0.9367, mIoU: 0.5876 Batch 60/200: Loss: 0.2185, PA: 0.9308, mIoU: 0.5671 Batch 70/200: Loss: 0.2704, PA: 0.9016, mIoU: 0.6225 Batch 80/200: Loss: 0.2581, PA: 0.8985, mIoU: 0.5452 Batch 90/200: Loss: 0.1633, PA: 0.9579, mIoU: 0.6808 Batch 100/200: Loss: 0.1822, PA: 0.9422, mIoU: 0.6333 Batch 110/200: Loss: 0.2671, PA: 0.8847, mIoU: 0.4714 Batch 120/200: Loss: 0.1905, PA: 0.9477, mIoU: 0.6029 Batch 130/200: Loss: 0.1746, PA: 0.9348, mIoU: 0.6901 Batch 140/200: Loss: 0.1510, PA: 0.9472, mIoU: 0.7404 Batch 150/200: Loss: 0.1981, PA: 0.9398, mIoU: 0.6603 Batch 160/200: Loss: 0.4107, PA: 0.8758, mIoU: 0.4689 Batch 170/200: Loss: 0.2790, PA: 0.9030, mIoU: 0.4561 Batch 180/200: Loss: 0.1606, PA: 0.9410, mIoU: 0.7067 Batch 190/200: Loss: 0.2833, PA: 0.9249, mIoU: 0.5815 Batch 200/200: Loss: 0.2018, PA: 0.9306, mIoU: 0.7184 Resumen Epoch 10: Tiempo: 400.95s Train Loss: 0.2164 | PA: 0.9220 | mIoU: 0.6145 Val Loss: 0.1798 | PA: 0.9405 | mIoU: 0.6807 Learning Rate: 0.000299 ✓ Modelo guardado (mIoU: 0.6807) Epoch 11/80 ---------------------------------------- Batch 10/200: Loss: 0.2268, PA: 0.8923, mIoU: 0.5445 Batch 20/200: Loss: 0.1425, PA: 0.9506, mIoU: 0.7533 Batch 30/200: Loss: 0.3565, PA: 0.8618, mIoU: 0.4652 Batch 40/200: Loss: 0.2637, PA: 0.8989, mIoU: 0.5464 Batch 50/200: Loss: 0.1492, PA: 0.9446, mIoU: 0.7318 Batch 60/200: Loss: 0.1867, PA: 0.9343, mIoU: 0.5722 Batch 70/200: Loss: 0.2093, PA: 0.9243, mIoU: 0.5922 Batch 80/200: Loss: 0.1476, PA: 0.9407, mIoU: 0.6889 Batch 90/200: Loss: 0.2200, PA: 0.9365, mIoU: 0.6244 Batch 100/200: Loss: 0.1250, PA: 0.9612, mIoU: 0.7893 Batch 110/200: Loss: 0.2398, PA: 0.8785, mIoU: 0.5192 Batch 120/200: Loss: 0.1806, PA: 0.9348, mIoU: 0.5854 Batch 130/200: Loss: 0.1910, PA: 0.9272, mIoU: 0.6201 Batch 140/200: Loss: 0.2173, PA: 0.9277, mIoU: 0.5960 Batch 150/200: Loss: 0.2577, PA: 0.8876, mIoU: 0.5066 Batch 160/200: Loss: 0.1792, PA: 0.9403, mIoU: 0.6330 Batch 170/200: Loss: 0.1875, PA: 0.9526, mIoU: 0.6252 Batch 180/200: Loss: 0.2162, PA: 0.9199, mIoU: 0.5497 Batch 190/200: Loss: 0.2522, PA: 0.8889, mIoU: 0.4990 Batch 200/200: Loss: 0.1912, PA: 0.9238, mIoU: 0.6690 Resumen Epoch 11: Tiempo: 418.49s Train Loss: 0.2185 | PA: 0.9225 | mIoU: 0.6131 Val Loss: 0.1971 | PA: 0.9353 | mIoU: 0.6583 Learning Rate: 0.000299 Epoch 12/80 ---------------------------------------- Batch 10/200: Loss: 0.2388, PA: 0.9021, mIoU: 0.5104 Batch 20/200: Loss: 0.1855, PA: 0.9340, mIoU: 0.6537 Batch 30/200: Loss: 0.1754, PA: 0.9330, mIoU: 0.7681 Batch 40/200: Loss: 0.1591, PA: 0.9431, mIoU: 0.6992 Batch 50/200: Loss: 0.2129, PA: 0.9207, mIoU: 0.5651 Batch 60/200: Loss: 0.1937, PA: 0.9280, mIoU: 0.6125 Batch 70/200: Loss: 0.1370, PA: 0.9662, mIoU: 0.7363 Batch 80/200: Loss: 0.2125, PA: 0.9323, mIoU: 0.5633 Batch 90/200: Loss: 0.2010, PA: 0.9289, mIoU: 0.7050 Batch 100/200: Loss: 0.2174, PA: 0.9083, mIoU: 0.5410 Batch 110/200: Loss: 0.1691, PA: 0.9410, mIoU: 0.6171 Batch 120/200: Loss: 0.2234, PA: 0.9305, mIoU: 0.5616 Batch 130/200: Loss: 0.3129, PA: 0.8822, mIoU: 0.5413 Batch 140/200: Loss: 0.1847, PA: 0.9514, mIoU: 0.5925 Batch 150/200: Loss: 0.2074, PA: 0.9225, mIoU: 0.5621 Batch 160/200: Loss: 0.2351, PA: 0.9252, mIoU: 0.5681 Batch 170/200: Loss: 0.1562, PA: 0.9540, mIoU: 0.7518 Batch 180/200: Loss: 0.1911, PA: 0.9281, mIoU: 0.6832 Batch 190/200: Loss: 0.1352, PA: 0.9679, mIoU: 0.6857 Batch 200/200: Loss: 0.3185, PA: 0.9051, mIoU: 0.5255 Resumen Epoch 12: Tiempo: 402.62s Train Loss: 0.2128 | PA: 0.9259 | mIoU: 0.6228 Val Loss: 0.1727 | PA: 0.9406 | mIoU: 0.6680 Learning Rate: 0.000298 Epoch 13/80 ---------------------------------------- Batch 10/200: Loss: 0.2193, PA: 0.9173, mIoU: 0.6258 Batch 20/200: Loss: 0.2857, PA: 0.8775, mIoU: 0.5886 Batch 30/200: Loss: 0.1531, PA: 0.9548, mIoU: 0.6492 Batch 40/200: Loss: 0.4464, PA: 0.8918, mIoU: 0.4789 Batch 50/200: Loss: 0.1252, PA: 0.9549, mIoU: 0.7378 Batch 60/200: Loss: 0.2186, PA: 0.9194, mIoU: 0.5884 Batch 70/200: Loss: 0.2334, PA: 0.8929, mIoU: 0.5856 Batch 80/200: Loss: 0.1847, PA: 0.9409, mIoU: 0.6956 Batch 90/200: Loss: 0.2588, PA: 0.9283, mIoU: 0.5700 Batch 100/200: Loss: 0.2073, PA: 0.9409, mIoU: 0.6639 Batch 110/200: Loss: 0.2636, PA: 0.9103, mIoU: 0.5381 Batch 120/200: Loss: 0.2588, PA: 0.9112, mIoU: 0.5036 Batch 130/200: Loss: 0.1731, PA: 0.9352, mIoU: 0.6689 Batch 140/200: Loss: 0.1362, PA: 0.9464, mIoU: 0.7291 Batch 150/200: Loss: 0.2864, PA: 0.8878, mIoU: 0.5770 Batch 160/200: Loss: 0.1782, PA: 0.9379, mIoU: 0.7038 Batch 170/200: Loss: 0.2949, PA: 0.9043, mIoU: 0.5236 Batch 180/200: Loss: 0.1032, PA: 0.9631, mIoU: 0.8406 Batch 190/200: Loss: 0.1793, PA: 0.9329, mIoU: 0.6333 Batch 200/200: Loss: 0.2153, PA: 0.9359, mIoU: 0.6627 Resumen Epoch 13: Tiempo: 399.16s Train Loss: 0.2005 | PA: 0.9293 | mIoU: 0.6363 Val Loss: 0.1710 | PA: 0.9433 | mIoU: 0.6778 Learning Rate: 0.000296 Epoch 14/80 ---------------------------------------- Batch 10/200: Loss: 0.1781, PA: 0.9351, mIoU: 0.6077 Batch 20/200: Loss: 0.3547, PA: 0.8856, mIoU: 0.5194 Batch 30/200: Loss: 0.2251, PA: 0.9175, mIoU: 0.5169 Batch 40/200: Loss: 0.1562, PA: 0.9336, mIoU: 0.7454 Batch 50/200: Loss: 0.1916, PA: 0.9063, mIoU: 0.6411 Batch 60/200: Loss: 0.1822, PA: 0.9213, mIoU: 0.6761 Batch 70/200: Loss: 0.1528, PA: 0.9586, mIoU: 0.6436 Batch 80/200: Loss: 0.1415, PA: 0.9413, mIoU: 0.6909 Batch 90/200: Loss: 0.2133, PA: 0.9179, mIoU: 0.5873 Batch 100/200: Loss: 0.1486, PA: 0.9443, mIoU: 0.6742 Batch 110/200: Loss: 0.1996, PA: 0.9510, mIoU: 0.6032 Batch 120/200: Loss: 0.1911, PA: 0.9378, mIoU: 0.6593 Batch 130/200: Loss: 0.2022, PA: 0.9347, mIoU: 0.6617 Batch 140/200: Loss: 0.2545, PA: 0.9224, mIoU: 0.5700 Batch 150/200: Loss: 0.1745, PA: 0.9356, mIoU: 0.6317 Batch 160/200: Loss: 0.1778, PA: 0.9250, mIoU: 0.6621 Batch 170/200: Loss: 0.2922, PA: 0.8819, mIoU: 0.5073 Batch 180/200: Loss: 0.1715, PA: 0.9422, mIoU: 0.6772 Batch 190/200: Loss: 0.1946, PA: 0.9080, mIoU: 0.6008 Batch 200/200: Loss: 0.1673, PA: 0.9462, mIoU: 0.6435 Resumen Epoch 14: Tiempo: 405.53s Train Loss: 0.1977 | PA: 0.9290 | mIoU: 0.6354 Val Loss: 0.1636 | PA: 0.9448 | mIoU: 0.6733 Learning Rate: 0.000295 Epoch 15/80 ---------------------------------------- Batch 10/200: Loss: 0.1636, PA: 0.9468, mIoU: 0.7165 Batch 20/200: Loss: 0.2272, PA: 0.9193, mIoU: 0.5586 Batch 30/200: Loss: 0.2127, PA: 0.9416, mIoU: 0.5761 Batch 40/200: Loss: 0.1514, PA: 0.9441, mIoU: 0.7652 Batch 50/200: Loss: 0.2050, PA: 0.9394, mIoU: 0.5605 Batch 60/200: Loss: 0.1560, PA: 0.9514, mIoU: 0.6803 Batch 70/200: Loss: 0.1469, PA: 0.9590, mIoU: 0.7883 Batch 80/200: Loss: 0.1968, PA: 0.9353, mIoU: 0.6285 Batch 90/200: Loss: 0.1778, PA: 0.9299, mIoU: 0.6433 Batch 100/200: Loss: 0.1675, PA: 0.9429, mIoU: 0.7632 Batch 110/200: Loss: 0.1455, PA: 0.9432, mIoU: 0.7040 Batch 120/200: Loss: 0.1884, PA: 0.9433, mIoU: 0.5985 Batch 130/200: Loss: 0.2126, PA: 0.9319, mIoU: 0.6666 Batch 140/200: Loss: 0.1971, PA: 0.9278, mIoU: 0.6342 Batch 150/200: Loss: 0.1235, PA: 0.9565, mIoU: 0.7556 Batch 160/200: Loss: 0.1559, PA: 0.9364, mIoU: 0.7173 Batch 170/200: Loss: 0.1973, PA: 0.9420, mIoU: 0.6178 Batch 180/200: Loss: 0.4343, PA: 0.8703, mIoU: 0.4656 Batch 190/200: Loss: 0.1890, PA: 0.9202, mIoU: 0.5911 Batch 200/200: Loss: 0.2045, PA: 0.9252, mIoU: 0.5950 Resumen Epoch 15: Tiempo: 403.68s Train Loss: 0.1923 | PA: 0.9327 | mIoU: 0.6506 Val Loss: 0.1663 | PA: 0.9416 | mIoU: 0.6868 Learning Rate: 0.000293 ✓ Modelo guardado (mIoU: 0.6868) Epoch 16/80 ---------------------------------------- Batch 10/200: Loss: 0.1320, PA: 0.9477, mIoU: 0.7824 Batch 20/200: Loss: 0.2379, PA: 0.9223, mIoU: 0.5615 Batch 30/200: Loss: 0.1524, PA: 0.9622, mIoU: 0.7832 Batch 40/200: Loss: 0.2683, PA: 0.9209, mIoU: 0.6466 Batch 50/200: Loss: 0.1436, PA: 0.9373, mIoU: 0.7080 Batch 60/200: Loss: 0.1422, PA: 0.9515, mIoU: 0.6836 Batch 70/200: Loss: 0.2403, PA: 0.9144, mIoU: 0.5726 Batch 80/200: Loss: 0.1669, PA: 0.9436, mIoU: 0.6885 Batch 90/200: Loss: 0.1604, PA: 0.9492, mIoU: 0.7248 Batch 100/200: Loss: 0.1829, PA: 0.9477, mIoU: 0.6056 Batch 110/200: Loss: 0.2011, PA: 0.9033, mIoU: 0.6410 Batch 120/200: Loss: 0.1982, PA: 0.9314, mIoU: 0.6554 Batch 130/200: Loss: 0.1493, PA: 0.9557, mIoU: 0.7049 Batch 140/200: Loss: 0.3367, PA: 0.8845, mIoU: 0.5417 Batch 150/200: Loss: 0.2455, PA: 0.9061, mIoU: 0.5866 Batch 160/200: Loss: 0.1689, PA: 0.9516, mIoU: 0.6725 Batch 170/200: Loss: 0.1364, PA: 0.9585, mIoU: 0.7333 Batch 180/200: Loss: 0.2842, PA: 0.9139, mIoU: 0.4580 Batch 190/200: Loss: 0.2440, PA: 0.9148, mIoU: 0.4886 Batch 200/200: Loss: 0.1264, PA: 0.9711, mIoU: 0.8547 Resumen Epoch 16: Tiempo: 405.53s Train Loss: 0.1911 | PA: 0.9335 | mIoU: 0.6526 Val Loss: 0.1917 | PA: 0.9412 | mIoU: 0.6677 Learning Rate: 0.000291 Epoch 17/80 ---------------------------------------- Batch 10/200: Loss: 0.2900, PA: 0.8979, mIoU: 0.5262 Batch 20/200: Loss: 0.1463, PA: 0.9522, mIoU: 0.7477 Batch 30/200: Loss: 0.1563, PA: 0.9370, mIoU: 0.6549 Batch 40/200: Loss: 0.2310, PA: 0.8857, mIoU: 0.6229 Batch 50/200: Loss: 0.2699, PA: 0.8920, mIoU: 0.5005 Batch 60/200: Loss: 0.2315, PA: 0.9389, mIoU: 0.5305 Batch 70/200: Loss: 0.1915, PA: 0.9259, mIoU: 0.6391 Batch 80/200: Loss: 0.1106, PA: 0.9602, mIoU: 0.7986 Batch 90/200: Loss: 0.1465, PA: 0.9542, mIoU: 0.6422 Batch 100/200: Loss: 0.2771, PA: 0.9092, mIoU: 0.6208 Batch 110/200: Loss: 0.1633, PA: 0.9544, mIoU: 0.6891 Batch 120/200: Loss: 0.1310, PA: 0.9446, mIoU: 0.7412 Batch 130/200: Loss: 0.3015, PA: 0.8835, mIoU: 0.5483 Batch 140/200: Loss: 0.1804, PA: 0.9203, mIoU: 0.6124 Batch 150/200: Loss: 0.2511, PA: 0.9191, mIoU: 0.6007 Batch 160/200: Loss: 0.1548, PA: 0.9522, mIoU: 0.6768 Batch 170/200: Loss: 0.2882, PA: 0.8963, mIoU: 0.6583 Batch 180/200: Loss: 0.1566, PA: 0.9446, mIoU: 0.7333 Batch 190/200: Loss: 0.1162, PA: 0.9558, mIoU: 0.7742 Batch 200/200: Loss: 0.1344, PA: 0.9532, mIoU: 0.7161 Resumen Epoch 17: Tiempo: 415.12s Train Loss: 0.1847 | PA: 0.9361 | mIoU: 0.6612 Val Loss: 0.1853 | PA: 0.9415 | mIoU: 0.6810 Learning Rate: 0.000289 ✓ Mejora significativa: 0.6810 > 0.6677 Epoch 18/80 ---------------------------------------- Batch 10/200: Loss: 0.2449, PA: 0.9289, mIoU: 0.6495 Batch 20/200: Loss: 0.1357, PA: 0.9413, mIoU: 0.7295 Batch 30/200: Loss: 0.1587, PA: 0.9591, mIoU: 0.6394 Batch 40/200: Loss: 0.1939, PA: 0.9295, mIoU: 0.5532 Batch 50/200: Loss: 0.3292, PA: 0.9207, mIoU: 0.5793 Batch 60/200: Loss: 0.1598, PA: 0.9482, mIoU: 0.6787 Batch 70/200: Loss: 0.1336, PA: 0.9578, mIoU: 0.7407 Batch 80/200: Loss: 0.1149, PA: 0.9575, mIoU: 0.7741 Batch 90/200: Loss: 0.1678, PA: 0.9310, mIoU: 0.7040 Batch 100/200: Loss: 0.1650, PA: 0.9386, mIoU: 0.6543 Batch 110/200: Loss: 0.1874, PA: 0.9356, mIoU: 0.6682 Batch 120/200: Loss: 0.1560, PA: 0.9447, mIoU: 0.6733 Batch 130/200: Loss: 0.1287, PA: 0.9596, mIoU: 0.7604 Batch 140/200: Loss: 0.1721, PA: 0.9412, mIoU: 0.6679 Batch 150/200: Loss: 0.1407, PA: 0.9390, mIoU: 0.7359 Batch 160/200: Loss: 0.1476, PA: 0.9449, mIoU: 0.6858 Batch 170/200: Loss: 0.2131, PA: 0.9296, mIoU: 0.5756 Batch 180/200: Loss: 0.1785, PA: 0.9352, mIoU: 0.6184 Batch 190/200: Loss: 0.1686, PA: 0.9420, mIoU: 0.6461 Batch 200/200: Loss: 0.3727, PA: 0.8686, mIoU: 0.4992 Resumen Epoch 18: Tiempo: 405.93s Train Loss: 0.1806 | PA: 0.9380 | mIoU: 0.6666 Val Loss: 0.1730 | PA: 0.9472 | mIoU: 0.6932 Learning Rate: 0.000286 ✓ Modelo guardado (mIoU: 0.6932) ✓ Mejora significativa: 0.6932 > 0.6810 Epoch 19/80 ---------------------------------------- Batch 10/200: Loss: 0.2039, PA: 0.9155, mIoU: 0.6689 Batch 20/200: Loss: 0.1199, PA: 0.9569, mIoU: 0.7507 Batch 30/200: Loss: 0.1012, PA: 0.9689, mIoU: 0.8239 Batch 40/200: Loss: 0.1030, PA: 0.9591, mIoU: 0.7737 Batch 50/200: Loss: 0.1341, PA: 0.9683, mIoU: 0.6911 Batch 60/200: Loss: 0.2874, PA: 0.8864, mIoU: 0.5489 Batch 70/200: Loss: 0.1582, PA: 0.9436, mIoU: 0.7147 Batch 80/200: Loss: 0.2656, PA: 0.9026, mIoU: 0.5449 Batch 90/200: Loss: 0.1565, PA: 0.9395, mIoU: 0.7026 Batch 100/200: Loss: 0.1890, PA: 0.9442, mIoU: 0.6291 Batch 110/200: Loss: 0.2100, PA: 0.9176, mIoU: 0.6069 Batch 120/200: Loss: 0.1472, PA: 0.9520, mIoU: 0.7530 Batch 130/200: Loss: 0.1864, PA: 0.9270, mIoU: 0.6217 Batch 140/200: Loss: 0.1527, PA: 0.9598, mIoU: 0.6575 Batch 150/200: Loss: 0.3849, PA: 0.8769, mIoU: 0.4642 Batch 160/200: Loss: 0.2086, PA: 0.9233, mIoU: 0.6365 Batch 170/200: Loss: 0.1031, PA: 0.9688, mIoU: 0.8021 Batch 180/200: Loss: 0.2029, PA: 0.9268, mIoU: 0.6610 Batch 190/200: Loss: 0.2077, PA: 0.9318, mIoU: 0.5994 Batch 200/200: Loss: 0.2934, PA: 0.8958, mIoU: 0.5472 Resumen Epoch 19: Tiempo: 405.24s Train Loss: 0.1800 | PA: 0.9372 | mIoU: 0.6658 Val Loss: 0.1649 | PA: 0.9423 | mIoU: 0.6792 Learning Rate: 0.000283 EarlyStopping: 1/15 sin mejora Epoch 20/80 ---------------------------------------- Batch 10/200: Loss: 0.1695, PA: 0.9570, mIoU: 0.6783 Batch 20/200: Loss: 0.2076, PA: 0.9228, mIoU: 0.5711 Batch 30/200: Loss: 0.2992, PA: 0.8989, mIoU: 0.5451 Batch 40/200: Loss: 0.2186, PA: 0.9133, mIoU: 0.6150 Batch 50/200: Loss: 0.1364, PA: 0.9504, mIoU: 0.7484 Batch 60/200: Loss: 0.1771, PA: 0.9540, mIoU: 0.5898 Batch 70/200: Loss: 0.1602, PA: 0.9578, mIoU: 0.6100 Batch 80/200: Loss: 0.1013, PA: 0.9570, mIoU: 0.7933 Batch 90/200: Loss: 0.1374, PA: 0.9581, mIoU: 0.7383 Batch 100/200: Loss: 0.2655, PA: 0.8954, mIoU: 0.5320 Batch 110/200: Loss: 0.1640, PA: 0.9400, mIoU: 0.7208 Batch 120/200: Loss: 0.1380, PA: 0.9641, mIoU: 0.7299 Batch 130/200: Loss: 0.1463, PA: 0.9366, mIoU: 0.6446 Batch 140/200: Loss: 0.3173, PA: 0.9196, mIoU: 0.6028 Batch 150/200: Loss: 0.1018, PA: 0.9722, mIoU: 0.7857 Batch 160/200: Loss: 0.1271, PA: 0.9569, mIoU: 0.7746 Batch 170/200: Loss: 0.1551, PA: 0.9348, mIoU: 0.7122 Batch 180/200: Loss: 0.1557, PA: 0.9417, mIoU: 0.7134 Batch 190/200: Loss: 0.1487, PA: 0.9501, mIoU: 0.7493 Batch 200/200: Loss: 0.1006, PA: 0.9609, mIoU: 0.8183 Resumen Epoch 20: Tiempo: 436.49s Train Loss: 0.1708 | PA: 0.9427 | mIoU: 0.6813 Val Loss: 0.1595 | PA: 0.9472 | mIoU: 0.6978 Learning Rate: 0.000280 ✓ Modelo guardado (mIoU: 0.6978) ✓ Mejora significativa: 0.6978 > 0.6932 Epoch 21/80 ---------------------------------------- Batch 10/200: Loss: 0.1404, PA: 0.9645, mIoU: 0.7936 Batch 20/200: Loss: 0.1323, PA: 0.9607, mIoU: 0.7615 Batch 30/200: Loss: 0.2855, PA: 0.9512, mIoU: 0.7019 Batch 40/200: Loss: 0.0967, PA: 0.9702, mIoU: 0.8521 Batch 50/200: Loss: 0.1582, PA: 0.9289, mIoU: 0.6793 Batch 60/200: Loss: 0.1853, PA: 0.9348, mIoU: 0.5916 Batch 70/200: Loss: 0.0816, PA: 0.9738, mIoU: 0.8686 Batch 80/200: Loss: 0.1889, PA: 0.9035, mIoU: 0.6235 Batch 90/200: Loss: 0.1689, PA: 0.9374, mIoU: 0.6692 Batch 100/200: Loss: 0.1986, PA: 0.9209, mIoU: 0.6625 Batch 110/200: Loss: 0.1115, PA: 0.9558, mIoU: 0.7437 Batch 120/200: Loss: 0.0957, PA: 0.9685, mIoU: 0.8076 Batch 130/200: Loss: 0.1542, PA: 0.9266, mIoU: 0.6691 Batch 140/200: Loss: 0.1427, PA: 0.9479, mIoU: 0.6675 Batch 150/200: Loss: 0.1280, PA: 0.9469, mIoU: 0.7478 Batch 160/200: Loss: 0.1914, PA: 0.9373, mIoU: 0.6155 Batch 170/200: Loss: 0.1522, PA: 0.9282, mIoU: 0.6684 Batch 180/200: Loss: 0.1602, PA: 0.9629, mIoU: 0.6245 Batch 190/200: Loss: 0.0992, PA: 0.9686, mIoU: 0.7999 Batch 200/200: Loss: 0.1188, PA: 0.9521, mIoU: 0.7691 Resumen Epoch 21: Tiempo: 391.74s Train Loss: 0.1756 | PA: 0.9400 | mIoU: 0.6758 Val Loss: 0.1658 | PA: 0.9436 | mIoU: 0.6761 Learning Rate: 0.000276 EarlyStopping: 1/15 sin mejora Epoch 22/80 ---------------------------------------- Batch 10/200: Loss: 0.2153, PA: 0.9396, mIoU: 0.6302 Batch 20/200: Loss: 0.1565, PA: 0.9562, mIoU: 0.7484 Batch 30/200: Loss: 0.1224, PA: 0.9652, mIoU: 0.8042 Batch 40/200: Loss: 0.2596, PA: 0.9014, mIoU: 0.5692 Batch 50/200: Loss: 0.2608, PA: 0.9360, mIoU: 0.5164 Batch 60/200: Loss: 0.1193, PA: 0.9630, mIoU: 0.7519 Batch 70/200: Loss: 0.1396, PA: 0.9559, mIoU: 0.7327 Batch 80/200: Loss: 0.1107, PA: 0.9574, mIoU: 0.7894 Batch 90/200: Loss: 0.1878, PA: 0.9415, mIoU: 0.6597 Batch 100/200: Loss: 0.1199, PA: 0.9738, mIoU: 0.6985 Batch 110/200: Loss: 0.1820, PA: 0.9405, mIoU: 0.6963 Batch 120/200: Loss: 0.1703, PA: 0.9414, mIoU: 0.6756 Batch 130/200: Loss: 0.1714, PA: 0.9380, mIoU: 0.7574 Batch 140/200: Loss: 0.1165, PA: 0.9551, mIoU: 0.7891 Batch 150/200: Loss: 0.2195, PA: 0.9193, mIoU: 0.5753 Batch 160/200: Loss: 0.1714, PA: 0.9611, mIoU: 0.6441 Batch 170/200: Loss: 0.0989, PA: 0.9638, mIoU: 0.8153 Batch 180/200: Loss: 0.0973, PA: 0.9689, mIoU: 0.8256 Batch 190/200: Loss: 0.2322, PA: 0.9298, mIoU: 0.5974 Batch 200/200: Loss: 0.1927, PA: 0.9447, mIoU: 0.6077 Resumen Epoch 22: Tiempo: 388.83s Train Loss: 0.1634 | PA: 0.9443 | mIoU: 0.6886 Val Loss: 0.1717 | PA: 0.9445 | mIoU: 0.6829 Learning Rate: 0.000273 EarlyStopping: 2/15 sin mejora Epoch 23/80 ---------------------------------------- Batch 10/200: Loss: 0.1746, PA: 0.9446, mIoU: 0.7732 Batch 20/200: Loss: 0.3269, PA: 0.8827, mIoU: 0.5572 Batch 30/200: Loss: 0.1471, PA: 0.9360, mIoU: 0.6632 Batch 40/200: Loss: 0.1844, PA: 0.9440, mIoU: 0.6411 Batch 50/200: Loss: 0.1968, PA: 0.9312, mIoU: 0.6178 Batch 60/200: Loss: 0.1846, PA: 0.9298, mIoU: 0.6056 Batch 70/200: Loss: 0.1448, PA: 0.9659, mIoU: 0.6665 Batch 80/200: Loss: 0.1791, PA: 0.9352, mIoU: 0.6451 Batch 90/200: Loss: 0.2211, PA: 0.9210, mIoU: 0.5401 Batch 100/200: Loss: 0.1695, PA: 0.9585, mIoU: 0.6303 Batch 110/200: Loss: 0.2264, PA: 0.9249, mIoU: 0.5941 Batch 120/200: Loss: 0.1791, PA: 0.9451, mIoU: 0.6278 Batch 130/200: Loss: 0.0937, PA: 0.9636, mIoU: 0.8004 Batch 140/200: Loss: 0.1462, PA: 0.9382, mIoU: 0.7074 Batch 150/200: Loss: 0.1530, PA: 0.9493, mIoU: 0.7028 Batch 160/200: Loss: 0.2804, PA: 0.9505, mIoU: 0.7354 Batch 170/200: Loss: 0.1838, PA: 0.9403, mIoU: 0.6305 Batch 180/200: Loss: 0.1383, PA: 0.9733, mIoU: 0.6944 Batch 190/200: Loss: 0.1159, PA: 0.9659, mIoU: 0.7882 Batch 200/200: Loss: 0.2549, PA: 0.9063, mIoU: 0.5310 Resumen Epoch 23: Tiempo: 396.67s Train Loss: 0.1625 | PA: 0.9462 | mIoU: 0.6967 Val Loss: 0.1614 | PA: 0.9501 | mIoU: 0.7150 Learning Rate: 0.000269 ✓ Modelo guardado (mIoU: 0.7150) ✓ Mejora significativa: 0.7150 > 0.6978 Epoch 24/80 ---------------------------------------- Batch 10/200: Loss: 0.1685, PA: 0.9309, mIoU: 0.6875 Batch 20/200: Loss: 0.1316, PA: 0.9471, mIoU: 0.7443 Batch 30/200: Loss: 0.0954, PA: 0.9604, mIoU: 0.7863 Batch 40/200: Loss: 0.1056, PA: 0.9620, mIoU: 0.7703 Batch 50/200: Loss: 0.1436, PA: 0.9385, mIoU: 0.7263 Batch 60/200: Loss: 0.1827, PA: 0.9540, mIoU: 0.6010 Batch 70/200: Loss: 0.2135, PA: 0.9340, mIoU: 0.6025 Batch 80/200: Loss: 0.1078, PA: 0.9697, mIoU: 0.8052 Batch 90/200: Loss: 0.2306, PA: 0.8900, mIoU: 0.5743 Batch 100/200: Loss: 0.1405, PA: 0.9596, mIoU: 0.6599 Batch 110/200: Loss: 0.1505, PA: 0.9590, mIoU: 0.6701 Batch 120/200: Loss: 0.1070, PA: 0.9608, mIoU: 0.8029 Batch 130/200: Loss: 0.2266, PA: 0.9323, mIoU: 0.5603 Batch 140/200: Loss: 0.1174, PA: 0.9520, mIoU: 0.7795 Batch 150/200: Loss: 0.3464, PA: 0.9144, mIoU: 0.4964 Batch 160/200: Loss: 0.1493, PA: 0.9569, mIoU: 0.7364 Batch 170/200: Loss: 0.1224, PA: 0.9573, mIoU: 0.7174 Batch 180/200: Loss: 0.2104, PA: 0.9334, mIoU: 0.6063 Batch 190/200: Loss: 0.1020, PA: 0.9666, mIoU: 0.8187 Batch 200/200: Loss: 0.1511, PA: 0.9491, mIoU: 0.7567 Resumen Epoch 24: Tiempo: 390.86s Train Loss: 0.1572 | PA: 0.9474 | mIoU: 0.7019 Val Loss: 0.1573 | PA: 0.9486 | mIoU: 0.6987 Learning Rate: 0.000265 EarlyStopping: 1/15 sin mejora Epoch 25/80 ---------------------------------------- Batch 10/200: Loss: 0.1341, PA: 0.9681, mIoU: 0.6692 Batch 20/200: Loss: 0.2075, PA: 0.9334, mIoU: 0.5932 Batch 30/200: Loss: 0.1031, PA: 0.9664, mIoU: 0.7853 Batch 40/200: Loss: 0.2155, PA: 0.9276, mIoU: 0.6164 Batch 50/200: Loss: 0.1657, PA: 0.9480, mIoU: 0.6461 Batch 60/200: Loss: 0.1348, PA: 0.9529, mIoU: 0.7174 Batch 70/200: Loss: 0.2103, PA: 0.9259, mIoU: 0.6248 Batch 80/200: Loss: 0.1520, PA: 0.9404, mIoU: 0.6974 Batch 90/200: Loss: 0.3568, PA: 0.9074, mIoU: 0.6173 Batch 100/200: Loss: 0.1099, PA: 0.9533, mIoU: 0.7813 Batch 110/200: Loss: 0.2359, PA: 0.9120, mIoU: 0.5784 Batch 120/200: Loss: 0.1760, PA: 0.9352, mIoU: 0.6190 Batch 130/200: Loss: 0.1350, PA: 0.9684, mIoU: 0.7046 Batch 140/200: Loss: 0.2471, PA: 0.9088, mIoU: 0.5436 Batch 150/200: Loss: 0.1753, PA: 0.9581, mIoU: 0.6969 Batch 160/200: Loss: 0.1892, PA: 0.9377, mIoU: 0.5910 Batch 170/200: Loss: 0.1085, PA: 0.9619, mIoU: 0.8082 Batch 180/200: Loss: 0.0930, PA: 0.9716, mIoU: 0.8216 Batch 190/200: Loss: 0.1560, PA: 0.9650, mIoU: 0.7774 Batch 200/200: Loss: 0.1720, PA: 0.9236, mIoU: 0.6898 Resumen Epoch 25: Tiempo: 389.05s Train Loss: 0.1574 | PA: 0.9470 | mIoU: 0.7033 Val Loss: 0.1746 | PA: 0.9438 | mIoU: 0.6679 Learning Rate: 0.000261 EarlyStopping: 2/15 sin mejora Epoch 26/80 ---------------------------------------- Batch 10/200: Loss: 0.1650, PA: 0.9384, mIoU: 0.6878 Batch 20/200: Loss: 0.1441, PA: 0.9425, mIoU: 0.7517 Batch 30/200: Loss: 0.1238, PA: 0.9536, mIoU: 0.7618 Batch 40/200: Loss: 0.1308, PA: 0.9579, mIoU: 0.6882 Batch 50/200: Loss: 0.1167, PA: 0.9626, mIoU: 0.7903 Batch 60/200: Loss: 0.2039, PA: 0.9132, mIoU: 0.5907 Batch 70/200: Loss: 0.1523, PA: 0.9556, mIoU: 0.6455 Batch 80/200: Loss: 0.1201, PA: 0.9613, mIoU: 0.7540 Batch 90/200: Loss: 0.1249, PA: 0.9707, mIoU: 0.6802 Batch 100/200: Loss: 0.1396, PA: 0.9675, mIoU: 0.7853 Batch 110/200: Loss: 0.1061, PA: 0.9571, mIoU: 0.7994 Batch 120/200: Loss: 0.3599, PA: 0.9102, mIoU: 0.6731 Batch 130/200: Loss: 0.0778, PA: 0.9725, mIoU: 0.8533 Batch 140/200: Loss: 0.2496, PA: 0.8911, mIoU: 0.6194 Batch 150/200: Loss: 0.1604, PA: 0.9336, mIoU: 0.6898 Batch 160/200: Loss: 0.1882, PA: 0.9314, mIoU: 0.7026 Batch 170/200: Loss: 0.0933, PA: 0.9684, mIoU: 0.8179 Batch 180/200: Loss: 0.1221, PA: 0.9563, mIoU: 0.7814 Batch 190/200: Loss: 0.1311, PA: 0.9578, mIoU: 0.7647 Batch 200/200: Loss: 0.1570, PA: 0.9397, mIoU: 0.6561 Resumen Epoch 26: Tiempo: 403.62s Train Loss: 0.1560 | PA: 0.9490 | mIoU: 0.7092 Val Loss: 0.1894 | PA: 0.9445 | mIoU: 0.6893 Learning Rate: 0.000256 EarlyStopping: 3/15 sin mejora Epoch 27/80 ---------------------------------------- Batch 10/200: Loss: 0.1413, PA: 0.9533, mIoU: 0.6630 Batch 20/200: Loss: 0.1430, PA: 0.9456, mIoU: 0.6998 Batch 30/200: Loss: 0.1561, PA: 0.9347, mIoU: 0.7198 Batch 40/200: Loss: 0.1592, PA: 0.9605, mIoU: 0.7659 Batch 50/200: Loss: 0.1864, PA: 0.9419, mIoU: 0.7150 Batch 60/200: Loss: 0.1701, PA: 0.9588, mIoU: 0.5593 Batch 70/200: Loss: 0.1259, PA: 0.9719, mIoU: 0.6734 Batch 80/200: Loss: 0.2439, PA: 0.9447, mIoU: 0.5947 Batch 90/200: Loss: 0.2367, PA: 0.9209, mIoU: 0.5812 Batch 100/200: Loss: 0.2912, PA: 0.9117, mIoU: 0.5440 Batch 110/200: Loss: 0.1189, PA: 0.9645, mIoU: 0.8119 Batch 120/200: Loss: 0.1050, PA: 0.9680, mIoU: 0.7978 Batch 130/200: Loss: 0.1247, PA: 0.9518, mIoU: 0.7806 Batch 140/200: Loss: 0.0919, PA: 0.9619, mIoU: 0.7828 Batch 150/200: Loss: 0.1394, PA: 0.9749, mIoU: 0.7307 Batch 160/200: Loss: 0.1166, PA: 0.9674, mIoU: 0.7341 Batch 170/200: Loss: 0.1673, PA: 0.9547, mIoU: 0.6594 Batch 180/200: Loss: 0.1343, PA: 0.9516, mIoU: 0.7283 Batch 190/200: Loss: 0.1154, PA: 0.9744, mIoU: 0.6992 Batch 200/200: Loss: 0.1748, PA: 0.9374, mIoU: 0.6522 Resumen Epoch 27: Tiempo: 392.79s Train Loss: 0.1483 | PA: 0.9502 | mIoU: 0.7121 Val Loss: 0.1731 | PA: 0.9467 | mIoU: 0.6971 Learning Rate: 0.000251 EarlyStopping: 4/15 sin mejora Epoch 28/80 ---------------------------------------- Batch 10/200: Loss: 0.0710, PA: 0.9700, mIoU: 0.8661 Batch 20/200: Loss: 0.0686, PA: 0.9764, mIoU: 0.8587 Batch 30/200: Loss: 0.2005, PA: 0.9190, mIoU: 0.6589 Batch 40/200: Loss: 0.0944, PA: 0.9631, mIoU: 0.8276 Batch 50/200: Loss: 0.1310, PA: 0.9688, mIoU: 0.7988 Batch 60/200: Loss: 0.0868, PA: 0.9706, mIoU: 0.8404 Batch 70/200: Loss: 0.1899, PA: 0.9176, mIoU: 0.6511 Batch 80/200: Loss: 0.1387, PA: 0.9680, mIoU: 0.8025 Batch 90/200: Loss: 0.0937, PA: 0.9685, mIoU: 0.8157 Batch 100/200: Loss: 0.1460, PA: 0.9579, mIoU: 0.6770 Batch 110/200: Loss: 0.1575, PA: 0.9418, mIoU: 0.5886 Batch 120/200: Loss: 0.1441, PA: 0.9689, mIoU: 0.7628 Batch 130/200: Loss: 0.1436, PA: 0.9498, mIoU: 0.7076 Batch 140/200: Loss: 0.1769, PA: 0.9475, mIoU: 0.6395 Batch 150/200: Loss: 0.1668, PA: 0.9262, mIoU: 0.6963 Batch 160/200: Loss: 0.3688, PA: 0.8898, mIoU: 0.4603 Batch 170/200: Loss: 0.1309, PA: 0.9586, mIoU: 0.7147 Batch 180/200: Loss: 0.1324, PA: 0.9491, mIoU: 0.7409 Batch 190/200: Loss: 0.1696, PA: 0.9346, mIoU: 0.7180 Batch 200/200: Loss: 0.1023, PA: 0.9685, mIoU: 0.8027 Resumen Epoch 28: Tiempo: 387.52s Train Loss: 0.1503 | PA: 0.9503 | mIoU: 0.7170 Val Loss: 0.1748 | PA: 0.9478 | mIoU: 0.7005 Learning Rate: 0.000246 EarlyStopping: 5/15 sin mejora Epoch 29/80 ---------------------------------------- Batch 10/200: Loss: 0.1038, PA: 0.9720, mIoU: 0.7676 Batch 20/200: Loss: 0.1518, PA: 0.9494, mIoU: 0.7296 Batch 30/200: Loss: 0.1598, PA: 0.9363, mIoU: 0.6672 Batch 40/200: Loss: 0.1190, PA: 0.9536, mIoU: 0.7898 Batch 50/200: Loss: 0.2494, PA: 0.9286, mIoU: 0.6609 Batch 60/200: Loss: 0.0864, PA: 0.9720, mIoU: 0.8109 Batch 70/200: Loss: 0.2874, PA: 0.9028, mIoU: 0.5951 Batch 80/200: Loss: 0.0865, PA: 0.9668, mIoU: 0.8185 Batch 90/200: Loss: 0.1580, PA: 0.9451, mIoU: 0.7161 Batch 100/200: Loss: 0.0993, PA: 0.9595, mIoU: 0.7960 Batch 110/200: Loss: 0.1095, PA: 0.9696, mIoU: 0.7710 Batch 120/200: Loss: 0.1529, PA: 0.9348, mIoU: 0.6695 Batch 130/200: Loss: 0.2003, PA: 0.9401, mIoU: 0.7207 Batch 140/200: Loss: 0.1243, PA: 0.9498, mIoU: 0.7169 Batch 150/200: Loss: 0.1705, PA: 0.9371, mIoU: 0.7188 Batch 160/200: Loss: 0.2947, PA: 0.8889, mIoU: 0.5356 Batch 170/200: Loss: 0.1883, PA: 0.9498, mIoU: 0.5824 Batch 180/200: Loss: 0.1915, PA: 0.9404, mIoU: 0.6659 Batch 190/200: Loss: 0.1247, PA: 0.9560, mIoU: 0.7465 Batch 200/200: Loss: 0.0826, PA: 0.9720, mIoU: 0.8442 Resumen Epoch 29: Tiempo: 410.24s Train Loss: 0.1466 | PA: 0.9527 | mIoU: 0.7203 Val Loss: 0.1589 | PA: 0.9503 | mIoU: 0.7073 Learning Rate: 0.000241 EarlyStopping: 6/15 sin mejora Epoch 30/80 ---------------------------------------- Batch 10/200: Loss: 0.0683, PA: 0.9767, mIoU: 0.8746 Batch 20/200: Loss: 0.1271, PA: 0.9669, mIoU: 0.6731 Batch 30/200: Loss: 0.1299, PA: 0.9470, mIoU: 0.7294 Batch 40/200: Loss: 0.1217, PA: 0.9432, mIoU: 0.6926 Batch 50/200: Loss: 0.2202, PA: 0.9329, mIoU: 0.6459 Batch 60/200: Loss: 0.1825, PA: 0.9410, mIoU: 0.7486 Batch 70/200: Loss: 0.1390, PA: 0.9501, mIoU: 0.6695 Batch 80/200: Loss: 0.1530, PA: 0.9509, mIoU: 0.6708 Batch 90/200: Loss: 0.0848, PA: 0.9707, mIoU: 0.8065 Batch 100/200: Loss: 0.2002, PA: 0.9572, mIoU: 0.7620 Batch 110/200: Loss: 0.1892, PA: 0.9487, mIoU: 0.6504 Batch 120/200: Loss: 0.0608, PA: 0.9797, mIoU: 0.8904 Batch 130/200: Loss: 0.1463, PA: 0.9331, mIoU: 0.6659 Batch 140/200: Loss: 0.0820, PA: 0.9671, mIoU: 0.8352 Batch 150/200: Loss: 0.1026, PA: 0.9788, mIoU: 0.7326 Batch 160/200: Loss: 0.1879, PA: 0.9566, mIoU: 0.5841 Batch 170/200: Loss: 0.1606, PA: 0.9464, mIoU: 0.6393 Batch 180/200: Loss: 0.1011, PA: 0.9665, mIoU: 0.7832 Batch 190/200: Loss: 0.1018, PA: 0.9633, mIoU: 0.7783 Batch 200/200: Loss: 0.1070, PA: 0.9591, mIoU: 0.7886 Resumen Epoch 30: Tiempo: 402.45s Train Loss: 0.1364 | PA: 0.9550 | mIoU: 0.7412 Val Loss: 0.1567 | PA: 0.9491 | mIoU: 0.7155 Learning Rate: 0.000236 ✓ Modelo guardado (mIoU: 0.7155) EarlyStopping: 7/15 sin mejora Epoch 31/80 ---------------------------------------- Batch 10/200: Loss: 0.0802, PA: 0.9739, mIoU: 0.8393 Batch 20/200: Loss: 0.1262, PA: 0.9716, mIoU: 0.7925 Batch 30/200: Loss: 0.1170, PA: 0.9747, mIoU: 0.8450 Batch 40/200: Loss: 0.1338, PA: 0.9548, mIoU: 0.7509 Batch 50/200: Loss: 0.1889, PA: 0.9574, mIoU: 0.6703 Batch 60/200: Loss: 0.0973, PA: 0.9546, mIoU: 0.8044 Batch 70/200: Loss: 0.1501, PA: 0.9412, mIoU: 0.6969 Batch 80/200: Loss: 0.1192, PA: 0.9623, mIoU: 0.7621 Batch 90/200: Loss: 0.1123, PA: 0.9627, mIoU: 0.7439 Batch 100/200: Loss: 0.2023, PA: 0.9219, mIoU: 0.6697 Batch 110/200: Loss: 0.1317, PA: 0.9547, mIoU: 0.7238 Batch 120/200: Loss: 0.1386, PA: 0.9642, mIoU: 0.7925 Batch 130/200: Loss: 0.0964, PA: 0.9641, mIoU: 0.7927 Batch 140/200: Loss: 0.1351, PA: 0.9514, mIoU: 0.7130 Batch 150/200: Loss: 0.0987, PA: 0.9666, mIoU: 0.7807 Batch 160/200: Loss: 0.1960, PA: 0.9488, mIoU: 0.6697 Batch 170/200: Loss: 0.1205, PA: 0.9529, mIoU: 0.7610 Batch 180/200: Loss: 0.0713, PA: 0.9742, mIoU: 0.8522 Batch 190/200: Loss: 0.1608, PA: 0.9415, mIoU: 0.6981 Batch 200/200: Loss: 0.1530, PA: 0.9366, mIoU: 0.6735 Resumen Epoch 31: Tiempo: 389.33s Train Loss: 0.1382 | PA: 0.9555 | mIoU: 0.7366 Val Loss: 0.1756 | PA: 0.9455 | mIoU: 0.6862 Learning Rate: 0.000231 EarlyStopping: 8/15 sin mejora Epoch 32/80 ---------------------------------------- Batch 10/200: Loss: 0.2326, PA: 0.9229, mIoU: 0.5814 Batch 20/200: Loss: 0.0982, PA: 0.9672, mIoU: 0.8237 Batch 30/200: Loss: 0.0977, PA: 0.9700, mIoU: 0.8031 Batch 40/200: Loss: 0.1244, PA: 0.9540, mIoU: 0.7734 Batch 50/200: Loss: 0.1024, PA: 0.9573, mIoU: 0.7674 Batch 60/200: Loss: 0.0672, PA: 0.9781, mIoU: 0.8666 Batch 70/200: Loss: 0.1008, PA: 0.9642, mIoU: 0.8252 Batch 80/200: Loss: 0.1233, PA: 0.9592, mIoU: 0.7450 Batch 90/200: Loss: 0.1465, PA: 0.9696, mIoU: 0.6243 Batch 100/200: Loss: 0.0805, PA: 0.9686, mIoU: 0.8302 Batch 110/200: Loss: 0.0928, PA: 0.9636, mIoU: 0.8150 Batch 120/200: Loss: 0.1507, PA: 0.9723, mIoU: 0.6382 Batch 130/200: Loss: 0.0882, PA: 0.9658, mIoU: 0.8256 Batch 140/200: Loss: 0.0920, PA: 0.9693, mIoU: 0.8172 Batch 150/200: Loss: 0.2211, PA: 0.9284, mIoU: 0.7141 Batch 160/200: Loss: 0.2341, PA: 0.9484, mIoU: 0.5420 Batch 170/200: Loss: 0.1038, PA: 0.9655, mIoU: 0.7891 Batch 180/200: Loss: 0.2001, PA: 0.9251, mIoU: 0.6658 Batch 190/200: Loss: 0.1384, PA: 0.9722, mIoU: 0.6351 Batch 200/200: Loss: 0.1198, PA: 0.9501, mIoU: 0.7695 Resumen Epoch 32: Tiempo: 395.43s Train Loss: 0.1346 | PA: 0.9554 | mIoU: 0.7430 Val Loss: 0.1725 | PA: 0.9469 | mIoU: 0.6939 Learning Rate: 0.000225 EarlyStopping: 9/15 sin mejora Epoch 33/80 ---------------------------------------- Batch 10/200: Loss: 0.1835, PA: 0.9531, mIoU: 0.7166 Batch 20/200: Loss: 0.1456, PA: 0.9380, mIoU: 0.6438 Batch 30/200: Loss: 0.1100, PA: 0.9536, mIoU: 0.7795 Batch 40/200: Loss: 0.0957, PA: 0.9677, mIoU: 0.8103 Batch 50/200: Loss: 0.1600, PA: 0.9434, mIoU: 0.6726 Batch 60/200: Loss: 0.1584, PA: 0.9427, mIoU: 0.6229 Batch 70/200: Loss: 0.1501, PA: 0.9639, mIoU: 0.7848 Batch 80/200: Loss: 0.1734, PA: 0.9213, mIoU: 0.6809 Batch 90/200: Loss: 0.0817, PA: 0.9774, mIoU: 0.8433 Batch 100/200: Loss: 0.0716, PA: 0.9759, mIoU: 0.8379 Batch 110/200: Loss: 0.1279, PA: 0.9669, mIoU: 0.6988 Batch 120/200: Loss: 0.1196, PA: 0.9542, mIoU: 0.7681 Batch 130/200: Loss: 0.0639, PA: 0.9785, mIoU: 0.8829 Batch 140/200: Loss: 0.1502, PA: 0.9534, mIoU: 0.8029 Batch 150/200: Loss: 0.1370, PA: 0.9596, mIoU: 0.6482 Batch 160/200: Loss: 0.0788, PA: 0.9693, mIoU: 0.8450 Batch 170/200: Loss: 0.0805, PA: 0.9699, mIoU: 0.8277 Batch 180/200: Loss: 0.1972, PA: 0.9355, mIoU: 0.6046 Batch 190/200: Loss: 0.0982, PA: 0.9588, mIoU: 0.8194 Batch 200/200: Loss: 0.1364, PA: 0.9587, mIoU: 0.7063 Resumen Epoch 33: Tiempo: 393.91s Train Loss: 0.1326 | PA: 0.9557 | mIoU: 0.7430 Val Loss: 0.1760 | PA: 0.9430 | mIoU: 0.6701 Learning Rate: 0.000219 EarlyStopping: 10/15 sin mejora Epoch 34/80 ---------------------------------------- Batch 10/200: Loss: 0.0697, PA: 0.9731, mIoU: 0.8693 Batch 20/200: Loss: 0.1439, PA: 0.9704, mIoU: 0.6403 Batch 30/200: Loss: 0.1287, PA: 0.9682, mIoU: 0.6650 Batch 40/200: Loss: 0.1252, PA: 0.9643, mIoU: 0.7271 Batch 50/200: Loss: 0.0843, PA: 0.9708, mIoU: 0.8444 Batch 60/200: Loss: 0.1329, PA: 0.9637, mIoU: 0.6962 Batch 70/200: Loss: 0.0790, PA: 0.9698, mIoU: 0.8158 Batch 80/200: Loss: 0.1117, PA: 0.9629, mIoU: 0.7553 Batch 90/200: Loss: 0.0975, PA: 0.9681, mIoU: 0.8206 Batch 100/200: Loss: 0.2939, PA: 0.9038, mIoU: 0.5606 Batch 110/200: Loss: 0.1156, PA: 0.9525, mIoU: 0.7738 Batch 120/200: Loss: 0.1492, PA: 0.9693, mIoU: 0.7247 Batch 130/200: Loss: 0.1206, PA: 0.9499, mIoU: 0.7408 Batch 140/200: Loss: 0.1430, PA: 0.9529, mIoU: 0.7903 Batch 150/200: Loss: 0.1435, PA: 0.9547, mIoU: 0.6540 Batch 160/200: Loss: 0.0772, PA: 0.9727, mIoU: 0.8542 Batch 170/200: Loss: 0.2347, PA: 0.9161, mIoU: 0.6619 Batch 180/200: Loss: 0.1467, PA: 0.9448, mIoU: 0.7749 Batch 190/200: Loss: 0.0871, PA: 0.9697, mIoU: 0.8416 Batch 200/200: Loss: 0.2055, PA: 0.9272, mIoU: 0.6035 Resumen Epoch 34: Tiempo: 394.23s Train Loss: 0.1321 | PA: 0.9577 | mIoU: 0.7435 Val Loss: 0.1754 | PA: 0.9477 | mIoU: 0.7165 Learning Rate: 0.000213 ✓ Modelo guardado (mIoU: 0.7165) ✓ Mejora significativa: 0.7165 > 0.7150 Epoch 35/80 ---------------------------------------- Batch 10/200: Loss: 0.1230, PA: 0.9538, mIoU: 0.7977 Batch 20/200: Loss: 0.0905, PA: 0.9785, mIoU: 0.7905 Batch 30/200: Loss: 0.1082, PA: 0.9719, mIoU: 0.7638 Batch 40/200: Loss: 0.1498, PA: 0.9626, mIoU: 0.7991 Batch 50/200: Loss: 0.1063, PA: 0.9633, mIoU: 0.7661 Batch 60/200: Loss: 0.1148, PA: 0.9507, mIoU: 0.7819 Batch 70/200: Loss: 0.1484, PA: 0.9557, mIoU: 0.6512 Batch 80/200: Loss: 0.1165, PA: 0.9591, mIoU: 0.7731 Batch 90/200: Loss: 0.1545, PA: 0.9543, mIoU: 0.6945 Batch 100/200: Loss: 0.1119, PA: 0.9636, mIoU: 0.7944 Batch 110/200: Loss: 0.0861, PA: 0.9615, mIoU: 0.8183 Batch 120/200: Loss: 0.1172, PA: 0.9649, mIoU: 0.8223 Batch 130/200: Loss: 0.1236, PA: 0.9584, mIoU: 0.7807 Batch 140/200: Loss: 0.1721, PA: 0.9496, mIoU: 0.6495 Batch 150/200: Loss: 0.0866, PA: 0.9732, mIoU: 0.8552 Batch 160/200: Loss: 0.0971, PA: 0.9623, mIoU: 0.8200 Batch 170/200: Loss: 0.1134, PA: 0.9638, mIoU: 0.7877 Batch 180/200: Loss: 0.1314, PA: 0.9699, mIoU: 0.7770 Batch 190/200: Loss: 0.2627, PA: 0.9220, mIoU: 0.5682 Batch 200/200: Loss: 0.1376, PA: 0.9576, mIoU: 0.7473 Resumen Epoch 35: Tiempo: 416.29s Train Loss: 0.1284 | PA: 0.9584 | mIoU: 0.7489 Val Loss: 0.1632 | PA: 0.9492 | mIoU: 0.7107 Learning Rate: 0.000207 EarlyStopping: 1/15 sin mejora Epoch 36/80 ---------------------------------------- Batch 10/200: Loss: 0.1073, PA: 0.9639, mIoU: 0.8353 Batch 20/200: Loss: 0.1650, PA: 0.9382, mIoU: 0.6244 Batch 30/200: Loss: 0.0944, PA: 0.9671, mIoU: 0.7690 Batch 40/200: Loss: 0.0935, PA: 0.9689, mIoU: 0.8505 Batch 50/200: Loss: 0.0711, PA: 0.9751, mIoU: 0.8302 Batch 60/200: Loss: 0.1494, PA: 0.9499, mIoU: 0.6647 Batch 70/200: Loss: 0.0823, PA: 0.9710, mIoU: 0.8172 Batch 80/200: Loss: 0.1602, PA: 0.9418, mIoU: 0.7217 Batch 90/200: Loss: 0.0953, PA: 0.9697, mIoU: 0.8116 Batch 100/200: Loss: 0.1123, PA: 0.9737, mIoU: 0.8681 Batch 110/200: Loss: 0.0851, PA: 0.9719, mIoU: 0.7854 Batch 120/200: Loss: 0.2468, PA: 0.9377, mIoU: 0.5980 Batch 130/200: Loss: 0.0923, PA: 0.9692, mIoU: 0.8037 Batch 140/200: Loss: 0.1307, PA: 0.9678, mIoU: 0.6544 Batch 150/200: Loss: 0.0600, PA: 0.9775, mIoU: 0.8888 Batch 160/200: Loss: 0.1053, PA: 0.9486, mIoU: 0.7415 Batch 170/200: Loss: 0.1634, PA: 0.9531, mIoU: 0.6399 Batch 180/200: Loss: 0.1224, PA: 0.9722, mIoU: 0.8037 Batch 190/200: Loss: 0.1368, PA: 0.9639, mIoU: 0.7999 Batch 200/200: Loss: 0.1753, PA: 0.9367, mIoU: 0.6861 Resumen Epoch 36: Tiempo: 398.94s Train Loss: 0.1228 | PA: 0.9604 | mIoU: 0.7626 Val Loss: 0.1690 | PA: 0.9486 | mIoU: 0.7085 Learning Rate: 0.000201 EarlyStopping: 2/15 sin mejora Epoch 37/80 ---------------------------------------- Batch 10/200: Loss: 0.1911, PA: 0.9410, mIoU: 0.6017 Batch 20/200: Loss: 0.1469, PA: 0.9529, mIoU: 0.6604 Batch 30/200: Loss: 0.1178, PA: 0.9755, mIoU: 0.8302 Batch 40/200: Loss: 0.1807, PA: 0.9399, mIoU: 0.5978 Batch 50/200: Loss: 0.1021, PA: 0.9586, mIoU: 0.7773 Batch 60/200: Loss: 0.1231, PA: 0.9720, mIoU: 0.6851 Batch 70/200: Loss: 0.1254, PA: 0.9728, mIoU: 0.8208 Batch 80/200: Loss: 0.1445, PA: 0.9592, mIoU: 0.6636 Batch 90/200: Loss: 0.1364, PA: 0.9497, mIoU: 0.6409 Batch 100/200: Loss: 0.0823, PA: 0.9678, mIoU: 0.8339 Batch 110/200: Loss: 0.2168, PA: 0.9222, mIoU: 0.6485 Batch 120/200: Loss: 0.1550, PA: 0.9556, mIoU: 0.7441 Batch 130/200: Loss: 0.1540, PA: 0.9437, mIoU: 0.6678 Batch 140/200: Loss: 0.1432, PA: 0.9759, mIoU: 0.7521 Batch 150/200: Loss: 0.0878, PA: 0.9653, mIoU: 0.8255 Batch 160/200: Loss: 0.1152, PA: 0.9627, mIoU: 0.7668 Batch 170/200: Loss: 0.1354, PA: 0.9531, mIoU: 0.6896 Batch 180/200: Loss: 0.1027, PA: 0.9738, mIoU: 0.8137 Batch 190/200: Loss: 0.0799, PA: 0.9685, mIoU: 0.8241 Batch 200/200: Loss: 0.1022, PA: 0.9697, mIoU: 0.8133 Resumen Epoch 37: Tiempo: 394.48s Train Loss: 0.1219 | PA: 0.9605 | mIoU: 0.7549 Val Loss: 0.1734 | PA: 0.9469 | mIoU: 0.6932 Learning Rate: 0.000195 EarlyStopping: 3/15 sin mejora Epoch 38/80 ---------------------------------------- Batch 10/200: Loss: 0.1522, PA: 0.9419, mIoU: 0.7202 Batch 20/200: Loss: 0.0946, PA: 0.9671, mIoU: 0.8335 Batch 30/200: Loss: 0.0973, PA: 0.9704, mIoU: 0.7926 Batch 40/200: Loss: 0.1879, PA: 0.9332, mIoU: 0.7187 Batch 50/200: Loss: 0.1663, PA: 0.9354, mIoU: 0.6545 Batch 60/200: Loss: 0.1161, PA: 0.9543, mIoU: 0.7580 Batch 70/200: Loss: 0.1704, PA: 0.9543, mIoU: 0.6267 Batch 80/200: Loss: 0.1036, PA: 0.9547, mIoU: 0.8111 Batch 90/200: Loss: 0.1144, PA: 0.9769, mIoU: 0.6860 Batch 100/200: Loss: 0.1380, PA: 0.9387, mIoU: 0.7100 Batch 110/200: Loss: 0.1311, PA: 0.9722, mIoU: 0.7021 Batch 120/200: Loss: 0.0825, PA: 0.9689, mIoU: 0.8400 Batch 130/200: Loss: 0.1006, PA: 0.9745, mIoU: 0.7523 Batch 140/200: Loss: 0.1010, PA: 0.9628, mIoU: 0.7888 Batch 150/200: Loss: 0.1307, PA: 0.9602, mIoU: 0.7241 Batch 160/200: Loss: 0.0912, PA: 0.9598, mIoU: 0.8241 Batch 170/200: Loss: 0.1735, PA: 0.9338, mIoU: 0.7364 Batch 180/200: Loss: 0.1169, PA: 0.9522, mIoU: 0.7611 Batch 190/200: Loss: 0.0894, PA: 0.9669, mIoU: 0.8246 Batch 200/200: Loss: 0.1025, PA: 0.9783, mIoU: 0.7218 Resumen Epoch 38: Tiempo: 413.32s Train Loss: 0.1233 | PA: 0.9600 | mIoU: 0.7571 Val Loss: 0.1707 | PA: 0.9499 | mIoU: 0.7141 Learning Rate: 0.000189 EarlyStopping: 4/15 sin mejora Epoch 39/80 ---------------------------------------- Batch 10/200: Loss: 0.1322, PA: 0.9665, mIoU: 0.8086 Batch 20/200: Loss: 0.0756, PA: 0.9683, mIoU: 0.8284 Batch 30/200: Loss: 0.0894, PA: 0.9707, mIoU: 0.7782 Batch 40/200: Loss: 0.1621, PA: 0.9431, mIoU: 0.6745 Batch 50/200: Loss: 0.1642, PA: 0.9657, mIoU: 0.7017 Batch 60/200: Loss: 0.1222, PA: 0.9560, mIoU: 0.7388 Batch 70/200: Loss: 0.1139, PA: 0.9645, mIoU: 0.7747 Batch 80/200: Loss: 0.1275, PA: 0.9692, mIoU: 0.6814 Batch 90/200: Loss: 0.1497, PA: 0.9643, mIoU: 0.7933 Batch 100/200: Loss: 0.0913, PA: 0.9688, mIoU: 0.8016 Batch 110/200: Loss: 0.1315, PA: 0.9497, mIoU: 0.7569 Batch 120/200: Loss: 0.1166, PA: 0.9569, mIoU: 0.7742 Batch 130/200: Loss: 0.2100, PA: 0.9386, mIoU: 0.6201 Batch 140/200: Loss: 0.1510, PA: 0.9639, mIoU: 0.6266 Batch 150/200: Loss: 0.0893, PA: 0.9694, mIoU: 0.8083 Batch 160/200: Loss: 0.1093, PA: 0.9582, mIoU: 0.8059 Batch 170/200: Loss: 0.0749, PA: 0.9772, mIoU: 0.8266 Batch 180/200: Loss: 0.0997, PA: 0.9564, mIoU: 0.8069 Batch 190/200: Loss: 0.1120, PA: 0.9632, mIoU: 0.7562 Batch 200/200: Loss: 0.0723, PA: 0.9755, mIoU: 0.8478 Resumen Epoch 39: Tiempo: 403.95s Train Loss: 0.1166 | PA: 0.9622 | mIoU: 0.7703 Val Loss: 0.2006 | PA: 0.9489 | mIoU: 0.7060 Learning Rate: 0.000182 EarlyStopping: 5/15 sin mejora Epoch 40/80 ---------------------------------------- Batch 10/200: Loss: 0.1219, PA: 0.9493, mIoU: 0.8039 Batch 20/200: Loss: 0.1221, PA: 0.9695, mIoU: 0.6883 Batch 30/200: Loss: 0.1005, PA: 0.9616, mIoU: 0.7798 Batch 40/200: Loss: 0.1297, PA: 0.9597, mIoU: 0.6863 Batch 50/200: Loss: 0.1157, PA: 0.9758, mIoU: 0.8319 Batch 60/200: Loss: 0.0926, PA: 0.9680, mIoU: 0.7966 Batch 70/200: Loss: 0.1189, PA: 0.9673, mIoU: 0.6998 Batch 80/200: Loss: 0.1413, PA: 0.9599, mIoU: 0.8368 Batch 90/200: Loss: 0.1066, PA: 0.9684, mIoU: 0.7816 Batch 100/200: Loss: 0.1380, PA: 0.9752, mIoU: 0.7299 Batch 110/200: Loss: 0.1274, PA: 0.9713, mIoU: 0.7974 Batch 120/200: Loss: 0.1086, PA: 0.9678, mIoU: 0.7818 Batch 130/200: Loss: 0.1001, PA: 0.9626, mIoU: 0.8031 Batch 140/200: Loss: 0.0802, PA: 0.9708, mIoU: 0.8225 Batch 150/200: Loss: 0.0695, PA: 0.9773, mIoU: 0.8468 Batch 160/200: Loss: 0.0992, PA: 0.9770, mIoU: 0.7687 Batch 170/200: Loss: 0.0830, PA: 0.9703, mIoU: 0.7983 Batch 180/200: Loss: 0.1343, PA: 0.9628, mIoU: 0.6528 Batch 190/200: Loss: 0.0622, PA: 0.9756, mIoU: 0.8771 Batch 200/200: Loss: 0.1582, PA: 0.9572, mIoU: 0.7398 Resumen Epoch 40: Tiempo: 394.61s Train Loss: 0.1143 | PA: 0.9632 | mIoU: 0.7725 Val Loss: 0.1914 | PA: 0.9464 | mIoU: 0.6998 Learning Rate: 0.000176 EarlyStopping: 6/15 sin mejora Epoch 41/80 ---------------------------------------- Batch 10/200: Loss: 0.0900, PA: 0.9670, mIoU: 0.8001 Batch 20/200: Loss: 0.0633, PA: 0.9771, mIoU: 0.8747 Batch 30/200: Loss: 0.0851, PA: 0.9707, mIoU: 0.7846 Batch 40/200: Loss: 0.0683, PA: 0.9763, mIoU: 0.8683 Batch 50/200: Loss: 0.1215, PA: 0.9446, mIoU: 0.7623 Batch 60/200: Loss: 0.1426, PA: 0.9688, mIoU: 0.7614 Batch 70/200: Loss: 0.1683, PA: 0.9698, mIoU: 0.7944 Batch 80/200: Loss: 0.0939, PA: 0.9631, mIoU: 0.8333 Batch 90/200: Loss: 0.0936, PA: 0.9604, mIoU: 0.7887 Batch 100/200: Loss: 0.0611, PA: 0.9771, mIoU: 0.8838 Batch 110/200: Loss: 0.0998, PA: 0.9626, mIoU: 0.8155 Batch 120/200: Loss: 0.1084, PA: 0.9615, mIoU: 0.7973 Batch 130/200: Loss: 0.0545, PA: 0.9788, mIoU: 0.9003 Batch 140/200: Loss: 0.1408, PA: 0.9499, mIoU: 0.6994 Batch 150/200: Loss: 0.1141, PA: 0.9666, mIoU: 0.7538 Batch 160/200: Loss: 0.0804, PA: 0.9713, mIoU: 0.8166 Batch 170/200: Loss: 0.0706, PA: 0.9726, mIoU: 0.8517 Batch 180/200: Loss: 0.0786, PA: 0.9745, mIoU: 0.8236 Batch 190/200: Loss: 0.1002, PA: 0.9560, mIoU: 0.7885 Batch 200/200: Loss: 0.1475, PA: 0.9455, mIoU: 0.6729 Resumen Epoch 41: Tiempo: 393.27s Train Loss: 0.1073 | PA: 0.9652 | mIoU: 0.7915 Val Loss: 0.1959 | PA: 0.9469 | mIoU: 0.6937 Learning Rate: 0.000170 EarlyStopping: 7/15 sin mejora Epoch 42/80 ---------------------------------------- Batch 10/200: Loss: 0.1350, PA: 0.9613, mIoU: 0.6821 Batch 20/200: Loss: 0.1466, PA: 0.9380, mIoU: 0.6471 Batch 30/200: Loss: 0.0781, PA: 0.9704, mIoU: 0.8683 Batch 40/200: Loss: 0.1475, PA: 0.9713, mIoU: 0.7460 Batch 50/200: Loss: 0.1138, PA: 0.9696, mIoU: 0.7180 Batch 60/200: Loss: 0.0510, PA: 0.9803, mIoU: 0.9026 Batch 70/200: Loss: 0.1581, PA: 0.9671, mIoU: 0.5873 Batch 80/200: Loss: 0.0925, PA: 0.9653, mIoU: 0.7856 Batch 90/200: Loss: 0.1124, PA: 0.9775, mIoU: 0.8324 Batch 100/200: Loss: 0.0782, PA: 0.9643, mIoU: 0.8377 Batch 110/200: Loss: 0.1383, PA: 0.9523, mIoU: 0.7773 Batch 120/200: Loss: 0.0913, PA: 0.9663, mIoU: 0.7897 Batch 130/200: Loss: 0.1519, PA: 0.9576, mIoU: 0.6370 Batch 140/200: Loss: 0.0665, PA: 0.9757, mIoU: 0.8488 Batch 150/200: Loss: 0.0611, PA: 0.9753, mIoU: 0.8702 Batch 160/200: Loss: 0.1414, PA: 0.9661, mIoU: 0.6565 Batch 170/200: Loss: 0.0794, PA: 0.9729, mIoU: 0.8381 Batch 180/200: Loss: 0.1204, PA: 0.9443, mIoU: 0.7487 Batch 190/200: Loss: 0.1581, PA: 0.9601, mIoU: 0.7508 Batch 200/200: Loss: 0.1570, PA: 0.9519, mIoU: 0.6429 Resumen Epoch 42: Tiempo: 396.27s Train Loss: 0.1062 | PA: 0.9655 | mIoU: 0.7866 Val Loss: 0.1647 | PA: 0.9523 | mIoU: 0.7260 Learning Rate: 0.000163 ✓ Modelo guardado (mIoU: 0.7260) ✓ Mejora significativa: 0.7260 > 0.7165 Epoch 43/80 ---------------------------------------- Batch 10/200: Loss: 0.0934, PA: 0.9722, mIoU: 0.8127 Batch 20/200: Loss: 0.1042, PA: 0.9685, mIoU: 0.7642 Batch 30/200: Loss: 0.0710, PA: 0.9725, mIoU: 0.8588 Batch 40/200: Loss: 0.0781, PA: 0.9697, mIoU: 0.8441 Batch 50/200: Loss: 0.0887, PA: 0.9679, mIoU: 0.8100 Batch 60/200: Loss: 0.1281, PA: 0.9626, mIoU: 0.6815 Batch 70/200: Loss: 0.0517, PA: 0.9814, mIoU: 0.8940 Batch 80/200: Loss: 0.0546, PA: 0.9755, mIoU: 0.8958 Batch 90/200: Loss: 0.0911, PA: 0.9644, mIoU: 0.7889 Batch 100/200: Loss: 0.1162, PA: 0.9484, mIoU: 0.7440 Batch 110/200: Loss: 0.0757, PA: 0.9785, mIoU: 0.8219 Batch 120/200: Loss: 0.1361, PA: 0.9510, mIoU: 0.6952 Batch 130/200: Loss: 0.0884, PA: 0.9661, mIoU: 0.8238 Batch 140/200: Loss: 0.1029, PA: 0.9748, mIoU: 0.8747 Batch 150/200: Loss: 0.1027, PA: 0.9593, mIoU: 0.7910 Batch 160/200: Loss: 0.1152, PA: 0.9566, mIoU: 0.7701 Batch 170/200: Loss: 0.2424, PA: 0.9267, mIoU: 0.7624 Batch 180/200: Loss: 0.0864, PA: 0.9726, mIoU: 0.7784 Batch 190/200: Loss: 0.0871, PA: 0.9701, mIoU: 0.8218 Batch 200/200: Loss: 0.1072, PA: 0.9620, mIoU: 0.7591 Resumen Epoch 43: Tiempo: 409.68s Train Loss: 0.1097 | PA: 0.9649 | mIoU: 0.7853 Val Loss: 0.1949 | PA: 0.9449 | mIoU: 0.6974 Learning Rate: 0.000157 EarlyStopping: 1/15 sin mejora Epoch 44/80 ---------------------------------------- Batch 10/200: Loss: 0.1070, PA: 0.9742, mIoU: 0.8741 Batch 20/200: Loss: 0.1235, PA: 0.9601, mIoU: 0.7724 Batch 30/200: Loss: 0.0631, PA: 0.9763, mIoU: 0.8671 Batch 40/200: Loss: 0.1292, PA: 0.9608, mIoU: 0.7031 Batch 50/200: Loss: 0.1275, PA: 0.9733, mIoU: 0.6448 Batch 60/200: Loss: 0.0835, PA: 0.9752, mIoU: 0.8062 Batch 70/200: Loss: 0.0834, PA: 0.9625, mIoU: 0.8327 Batch 80/200: Loss: 0.1137, PA: 0.9522, mIoU: 0.7893 Batch 90/200: Loss: 0.0987, PA: 0.9748, mIoU: 0.7537 Batch 100/200: Loss: 0.0732, PA: 0.9710, mIoU: 0.8414 Batch 110/200: Loss: 0.1508, PA: 0.9670, mIoU: 0.7701 Batch 120/200: Loss: 0.0969, PA: 0.9630, mIoU: 0.7810 Batch 130/200: Loss: 0.0843, PA: 0.9675, mIoU: 0.8303 Batch 140/200: Loss: 0.0594, PA: 0.9764, mIoU: 0.8879 Batch 150/200: Loss: 0.0803, PA: 0.9691, mIoU: 0.8067 Batch 160/200: Loss: 0.1008, PA: 0.9785, mIoU: 0.7467 Batch 170/200: Loss: 0.0548, PA: 0.9801, mIoU: 0.8749 Batch 180/200: Loss: 0.1316, PA: 0.9751, mIoU: 0.7722 Batch 190/200: Loss: 0.1238, PA: 0.9509, mIoU: 0.7671 Batch 200/200: Loss: 0.1298, PA: 0.9652, mIoU: 0.6802 Resumen Epoch 44: Tiempo: 396.61s Train Loss: 0.1042 | PA: 0.9666 | mIoU: 0.7921 Val Loss: 0.2182 | PA: 0.9407 | mIoU: 0.6741 Learning Rate: 0.000150 EarlyStopping: 2/15 sin mejora Epoch 45/80 ---------------------------------------- Batch 10/200: Loss: 0.0799, PA: 0.9669, mIoU: 0.8186 Batch 20/200: Loss: 0.0811, PA: 0.9717, mIoU: 0.8295 Batch 30/200: Loss: 0.1176, PA: 0.9752, mIoU: 0.8269 Batch 40/200: Loss: 0.1096, PA: 0.9621, mIoU: 0.7865 Batch 50/200: Loss: 0.0915, PA: 0.9685, mIoU: 0.8332 Batch 60/200: Loss: 0.0848, PA: 0.9649, mIoU: 0.8065 Batch 70/200: Loss: 0.1601, PA: 0.9498, mIoU: 0.7013 Batch 80/200: Loss: 0.0621, PA: 0.9730, mIoU: 0.8731 Batch 90/200: Loss: 0.1390, PA: 0.9752, mIoU: 0.7589 Batch 100/200: Loss: 0.1005, PA: 0.9629, mIoU: 0.7876 Batch 110/200: Loss: 0.1064, PA: 0.9664, mIoU: 0.7926 Batch 120/200: Loss: 0.0657, PA: 0.9779, mIoU: 0.8651 Batch 130/200: Loss: 0.0784, PA: 0.9719, mIoU: 0.8417 Batch 140/200: Loss: 0.0831, PA: 0.9705, mIoU: 0.8108 Batch 150/200: Loss: 0.1174, PA: 0.9543, mIoU: 0.7595 Batch 160/200: Loss: 0.0619, PA: 0.9721, mIoU: 0.8666 Batch 170/200: Loss: 0.1092, PA: 0.9706, mIoU: 0.8802 Batch 180/200: Loss: 0.0885, PA: 0.9711, mIoU: 0.8056 Batch 190/200: Loss: 0.2620, PA: 0.9291, mIoU: 0.5709 Batch 200/200: Loss: 0.0822, PA: 0.9648, mIoU: 0.8118 Resumen Epoch 45: Tiempo: 368.26s Train Loss: 0.1087 | PA: 0.9661 | mIoU: 0.7885 Val Loss: 0.1875 | PA: 0.9472 | mIoU: 0.6995 Learning Rate: 0.000143 EarlyStopping: 3/15 sin mejora Epoch 46/80 ---------------------------------------- Batch 10/200: Loss: 0.1634, PA: 0.9552, mIoU: 0.7783 Batch 20/200: Loss: 0.1698, PA: 0.9482, mIoU: 0.7453 Batch 30/200: Loss: 0.1370, PA: 0.9738, mIoU: 0.6378 Batch 40/200: Loss: 0.0843, PA: 0.9674, mIoU: 0.8372 Batch 50/200: Loss: 0.0850, PA: 0.9668, mIoU: 0.8260 Batch 60/200: Loss: 0.1105, PA: 0.9748, mIoU: 0.8657 Batch 70/200: Loss: 0.0612, PA: 0.9751, mIoU: 0.8754 Batch 80/200: Loss: 0.1303, PA: 0.9491, mIoU: 0.7427 Batch 90/200: Loss: 0.0675, PA: 0.9779, mIoU: 0.8416 Batch 100/200: Loss: 0.0916, PA: 0.9722, mIoU: 0.7893 Batch 110/200: Loss: 0.1449, PA: 0.9557, mIoU: 0.7548 Batch 120/200: Loss: 0.1026, PA: 0.9606, mIoU: 0.7807 Batch 130/200: Loss: 0.0634, PA: 0.9794, mIoU: 0.8512 Batch 140/200: Loss: 0.1500, PA: 0.9627, mIoU: 0.7359 Batch 150/200: Loss: 0.0717, PA: 0.9732, mIoU: 0.8473 Batch 160/200: Loss: 0.1156, PA: 0.9754, mIoU: 0.8216 Batch 170/200: Loss: 0.0785, PA: 0.9643, mIoU: 0.8293 Batch 180/200: Loss: 0.0763, PA: 0.9691, mIoU: 0.8249 Batch 190/200: Loss: 0.0971, PA: 0.9652, mIoU: 0.7710 Batch 200/200: Loss: 0.1124, PA: 0.9658, mIoU: 0.7774 Resumen Epoch 46: Tiempo: 383.49s Train Loss: 0.1050 | PA: 0.9665 | mIoU: 0.7935 Val Loss: 0.1810 | PA: 0.9479 | mIoU: 0.7057 Learning Rate: 0.000137 EarlyStopping: 4/15 sin mejora Epoch 47/80 ---------------------------------------- Batch 10/200: Loss: 0.0571, PA: 0.9787, mIoU: 0.8834 Batch 20/200: Loss: 0.0929, PA: 0.9638, mIoU: 0.8020 Batch 30/200: Loss: 0.1090, PA: 0.9589, mIoU: 0.7567 Batch 40/200: Loss: 0.0696, PA: 0.9740, mIoU: 0.8222 Batch 50/200: Loss: 0.0514, PA: 0.9798, mIoU: 0.8886 Batch 60/200: Loss: 0.1084, PA: 0.9741, mIoU: 0.8623 Batch 70/200: Loss: 0.0650, PA: 0.9756, mIoU: 0.8532 Batch 80/200: Loss: 0.0827, PA: 0.9755, mIoU: 0.8048 Batch 90/200: Loss: 0.1429, PA: 0.9687, mIoU: 0.6127 Batch 100/200: Loss: 0.0792, PA: 0.9742, mIoU: 0.8276 Batch 110/200: Loss: 0.0626, PA: 0.9790, mIoU: 0.8603 Batch 120/200: Loss: 0.0791, PA: 0.9768, mIoU: 0.8268 Batch 130/200: Loss: 0.1135, PA: 0.9614, mIoU: 0.7577 Batch 140/200: Loss: 0.1290, PA: 0.9686, mIoU: 0.8120 Batch 150/200: Loss: 0.0751, PA: 0.9710, mIoU: 0.8373 Batch 160/200: Loss: 0.1116, PA: 0.9534, mIoU: 0.7941 Batch 170/200: Loss: 0.1427, PA: 0.9665, mIoU: 0.6555 Batch 180/200: Loss: 0.0758, PA: 0.9727, mIoU: 0.8467 Batch 190/200: Loss: 0.0823, PA: 0.9730, mIoU: 0.8159 Batch 200/200: Loss: 0.1395, PA: 0.9606, mIoU: 0.8116 Resumen Epoch 47: Tiempo: 378.08s Train Loss: 0.1015 | PA: 0.9685 | mIoU: 0.7989 Val Loss: 0.1735 | PA: 0.9490 | mIoU: 0.7096 Learning Rate: 0.000130 EarlyStopping: 5/15 sin mejora Epoch 48/80 ---------------------------------------- Batch 10/200: Loss: 0.0580, PA: 0.9749, mIoU: 0.8834 Batch 20/200: Loss: 0.1246, PA: 0.9677, mIoU: 0.7099 Batch 30/200: Loss: 0.1230, PA: 0.9749, mIoU: 0.8031 Batch 40/200: Loss: 0.1123, PA: 0.9598, mIoU: 0.7618 Batch 50/200: Loss: 0.1232, PA: 0.9705, mIoU: 0.8325 Batch 60/200: Loss: 0.0946, PA: 0.9632, mIoU: 0.7871 Batch 70/200: Loss: 0.1064, PA: 0.9669, mIoU: 0.8188 Batch 80/200: Loss: 0.0904, PA: 0.9723, mIoU: 0.7853 Batch 90/200: Loss: 0.1185, PA: 0.9661, mIoU: 0.7256 Batch 100/200: Loss: 0.0912, PA: 0.9656, mIoU: 0.7995 Batch 110/200: Loss: 0.0797, PA: 0.9815, mIoU: 0.8360 Batch 120/200: Loss: 0.0619, PA: 0.9752, mIoU: 0.8771 Batch 130/200: Loss: 0.1108, PA: 0.9591, mIoU: 0.7862 Batch 140/200: Loss: 0.1145, PA: 0.9618, mIoU: 0.7744 Batch 150/200: Loss: 0.1080, PA: 0.9758, mIoU: 0.8615 Batch 160/200: Loss: 0.0920, PA: 0.9696, mIoU: 0.7795 Batch 170/200: Loss: 0.0590, PA: 0.9772, mIoU: 0.8740 Batch 180/200: Loss: 0.1617, PA: 0.9545, mIoU: 0.6624 Batch 190/200: Loss: 0.1139, PA: 0.9795, mIoU: 0.8075 Batch 200/200: Loss: 0.1164, PA: 0.9475, mIoU: 0.7949 Resumen Epoch 48: Tiempo: 376.28s Train Loss: 0.1044 | PA: 0.9671 | mIoU: 0.7972 Val Loss: 0.1772 | PA: 0.9469 | mIoU: 0.6957 Learning Rate: 0.000124 EarlyStopping: 6/15 sin mejora Epoch 49/80 ---------------------------------------- Batch 10/200: Loss: 0.0717, PA: 0.9753, mIoU: 0.8325 Batch 20/200: Loss: 0.0800, PA: 0.9671, mIoU: 0.8505 Batch 30/200: Loss: 0.0637, PA: 0.9767, mIoU: 0.8583 Batch 40/200: Loss: 0.1720, PA: 0.9427, mIoU: 0.6694 Batch 50/200: Loss: 0.0692, PA: 0.9751, mIoU: 0.8256 Batch 60/200: Loss: 0.0749, PA: 0.9742, mIoU: 0.8136 Batch 70/200: Loss: 0.1420, PA: 0.9679, mIoU: 0.7599 Batch 80/200: Loss: 0.0676, PA: 0.9701, mIoU: 0.8624 Batch 90/200: Loss: 0.0455, PA: 0.9806, mIoU: 0.8968 Batch 100/200: Loss: 0.0858, PA: 0.9612, mIoU: 0.8000 Batch 110/200: Loss: 0.1338, PA: 0.9659, mIoU: 0.7899 Batch 120/200: Loss: 0.0746, PA: 0.9685, mIoU: 0.8610 Batch 130/200: Loss: 0.0632, PA: 0.9756, mIoU: 0.8682 Batch 140/200: Loss: 0.0705, PA: 0.9763, mIoU: 0.8402 Batch 150/200: Loss: 0.0822, PA: 0.9724, mIoU: 0.8259 Batch 160/200: Loss: 0.0753, PA: 0.9735, mIoU: 0.8122 Batch 170/200: Loss: 0.1089, PA: 0.9741, mIoU: 0.8508 Batch 180/200: Loss: 0.0997, PA: 0.9664, mIoU: 0.7676 Batch 190/200: Loss: 0.1921, PA: 0.9497, mIoU: 0.6207 Batch 200/200: Loss: 0.0650, PA: 0.9781, mIoU: 0.8525 Resumen Epoch 49: Tiempo: 384.56s Train Loss: 0.0977 | PA: 0.9693 | mIoU: 0.8054 Val Loss: 0.1985 | PA: 0.9470 | mIoU: 0.6982 Learning Rate: 0.000118 EarlyStopping: 7/15 sin mejora Epoch 50/80 ---------------------------------------- Batch 10/200: Loss: 0.0653, PA: 0.9761, mIoU: 0.8571 Batch 20/200: Loss: 0.1200, PA: 0.9720, mIoU: 0.8499 Batch 30/200: Loss: 0.1238, PA: 0.9663, mIoU: 0.7178 Batch 40/200: Loss: 0.0470, PA: 0.9807, mIoU: 0.8949 Batch 50/200: Loss: 0.1218, PA: 0.9738, mIoU: 0.8195 Batch 60/200: Loss: 0.0903, PA: 0.9732, mIoU: 0.7820 Batch 70/200: Loss: 0.1252, PA: 0.9585, mIoU: 0.7650 Batch 80/200: Loss: 0.1096, PA: 0.9548, mIoU: 0.7575 Batch 90/200: Loss: 0.1255, PA: 0.9732, mIoU: 0.7878 Batch 100/200: Loss: 0.2449, PA: 0.9321, mIoU: 0.6547 Batch 110/200: Loss: 0.0906, PA: 0.9666, mIoU: 0.8432 Batch 120/200: Loss: 0.0759, PA: 0.9693, mIoU: 0.8509 Batch 130/200: Loss: 0.0550, PA: 0.9781, mIoU: 0.8897 Batch 140/200: Loss: 0.0999, PA: 0.9797, mIoU: 0.8806 Batch 150/200: Loss: 0.0677, PA: 0.9760, mIoU: 0.8371 Batch 160/200: Loss: 0.0648, PA: 0.9715, mIoU: 0.8623 Batch 170/200: Loss: 0.0793, PA: 0.9731, mIoU: 0.8327 Batch 180/200: Loss: 0.0767, PA: 0.9732, mIoU: 0.8247 Batch 190/200: Loss: 0.0524, PA: 0.9776, mIoU: 0.8871 Batch 200/200: Loss: 0.0787, PA: 0.9726, mIoU: 0.8237 Resumen Epoch 50: Tiempo: 382.30s Train Loss: 0.0959 | PA: 0.9695 | mIoU: 0.8124 Val Loss: 0.1989 | PA: 0.9476 | mIoU: 0.7028 Learning Rate: 0.000111 EarlyStopping: 8/15 sin mejora Epoch 51/80 ---------------------------------------- Batch 10/200: Loss: 0.1348, PA: 0.9646, mIoU: 0.6634 Batch 20/200: Loss: 0.0594, PA: 0.9798, mIoU: 0.8635 Batch 30/200: Loss: 0.0637, PA: 0.9757, mIoU: 0.8611 Batch 40/200: Loss: 0.1174, PA: 0.9622, mIoU: 0.7681 Batch 50/200: Loss: 0.0715, PA: 0.9754, mIoU: 0.8643 Batch 60/200: Loss: 0.0706, PA: 0.9764, mIoU: 0.8653 Batch 70/200: Loss: 0.1023, PA: 0.9778, mIoU: 0.8727 Batch 80/200: Loss: 0.1328, PA: 0.9660, mIoU: 0.6853 Batch 90/200: Loss: 0.0504, PA: 0.9798, mIoU: 0.8861 Batch 100/200: Loss: 0.0780, PA: 0.9688, mIoU: 0.8319 Batch 110/200: Loss: 0.0801, PA: 0.9669, mIoU: 0.8404 Batch 120/200: Loss: 0.1870, PA: 0.9674, mIoU: 0.7418 Batch 130/200: Loss: 0.0795, PA: 0.9776, mIoU: 0.8135 Batch 140/200: Loss: 0.1080, PA: 0.9667, mIoU: 0.7658 Batch 150/200: Loss: 0.2125, PA: 0.9350, mIoU: 0.6755 Batch 160/200: Loss: 0.0684, PA: 0.9719, mIoU: 0.8578 Batch 170/200: Loss: 0.1413, PA: 0.9610, mIoU: 0.8359 Batch 180/200: Loss: 0.0596, PA: 0.9776, mIoU: 0.8697 Batch 190/200: Loss: 0.1294, PA: 0.9782, mIoU: 0.7540 Batch 200/200: Loss: 0.1051, PA: 0.9638, mIoU: 0.8361 Resumen Epoch 51: Tiempo: 414.62s Train Loss: 0.0987 | PA: 0.9693 | mIoU: 0.8086 Val Loss: 0.1861 | PA: 0.9475 | mIoU: 0.7073 Learning Rate: 0.000105 EarlyStopping: 9/15 sin mejora Epoch 52/80 ---------------------------------------- Batch 10/200: Loss: 0.1170, PA: 0.9695, mIoU: 0.8365 Batch 20/200: Loss: 0.0825, PA: 0.9737, mIoU: 0.8273 Batch 30/200: Loss: 0.0787, PA: 0.9728, mIoU: 0.8121 Batch 40/200: Loss: 0.1211, PA: 0.9540, mIoU: 0.7810 Batch 50/200: Loss: 0.1260, PA: 0.9591, mIoU: 0.7395 Batch 60/200: Loss: 0.1302, PA: 0.9528, mIoU: 0.6802 Batch 70/200: Loss: 0.0612, PA: 0.9779, mIoU: 0.8852 Batch 80/200: Loss: 0.0909, PA: 0.9651, mIoU: 0.8409 Batch 90/200: Loss: 0.0761, PA: 0.9751, mIoU: 0.8133 Batch 100/200: Loss: 0.0928, PA: 0.9663, mIoU: 0.7847 Batch 110/200: Loss: 0.0634, PA: 0.9699, mIoU: 0.8697 Batch 120/200: Loss: 0.1039, PA: 0.9675, mIoU: 0.7591 Batch 130/200: Loss: 0.1088, PA: 0.9753, mIoU: 0.8434 Batch 140/200: Loss: 0.2350, PA: 0.9389, mIoU: 0.5826 Batch 150/200: Loss: 0.0816, PA: 0.9761, mIoU: 0.8225 Batch 160/200: Loss: 0.0591, PA: 0.9755, mIoU: 0.8774 Batch 170/200: Loss: 0.0633, PA: 0.9768, mIoU: 0.8573 Batch 180/200: Loss: 0.1200, PA: 0.9705, mIoU: 0.6942 Batch 190/200: Loss: 0.0640, PA: 0.9805, mIoU: 0.8604 Batch 200/200: Loss: 0.0478, PA: 0.9813, mIoU: 0.9122 Resumen Epoch 52: Tiempo: 361.75s Train Loss: 0.0916 | PA: 0.9710 | mIoU: 0.8179 Val Loss: 0.2006 | PA: 0.9447 | mIoU: 0.6935 Learning Rate: 0.000099 EarlyStopping: 10/15 sin mejora Epoch 53/80 ---------------------------------------- Batch 10/200: Loss: 0.0834, PA: 0.9707, mIoU: 0.7869 Batch 20/200: Loss: 0.1123, PA: 0.9591, mIoU: 0.7475 Batch 30/200: Loss: 0.0504, PA: 0.9768, mIoU: 0.8918 Batch 40/200: Loss: 0.1139, PA: 0.9748, mIoU: 0.6911 Batch 50/200: Loss: 0.0517, PA: 0.9816, mIoU: 0.8782 Batch 60/200: Loss: 0.0724, PA: 0.9764, mIoU: 0.8355 Batch 70/200: Loss: 0.0622, PA: 0.9759, mIoU: 0.8645 Batch 80/200: Loss: 0.0895, PA: 0.9746, mIoU: 0.7995 Batch 90/200: Loss: 0.1166, PA: 0.9733, mIoU: 0.8125 Batch 100/200: Loss: 0.0669, PA: 0.9760, mIoU: 0.8465 Batch 110/200: Loss: 0.0802, PA: 0.9686, mIoU: 0.8536 Batch 120/200: Loss: 0.0548, PA: 0.9793, mIoU: 0.8445 Batch 130/200: Loss: 0.1080, PA: 0.9780, mIoU: 0.8709 Batch 140/200: Loss: 0.0894, PA: 0.9715, mIoU: 0.7994 Batch 150/200: Loss: 0.0512, PA: 0.9817, mIoU: 0.8979 Batch 160/200: Loss: 0.0590, PA: 0.9784, mIoU: 0.8691 Batch 170/200: Loss: 0.0584, PA: 0.9772, mIoU: 0.8681 Batch 180/200: Loss: 0.1262, PA: 0.9653, mIoU: 0.8315 Batch 190/200: Loss: 0.1137, PA: 0.9622, mIoU: 0.7358 Batch 200/200: Loss: 0.0663, PA: 0.9747, mIoU: 0.8583 Resumen Epoch 53: Tiempo: 408.47s Train Loss: 0.0920 | PA: 0.9708 | mIoU: 0.8198 Val Loss: 0.1909 | PA: 0.9504 | mIoU: 0.7126 Learning Rate: 0.000093 EarlyStopping: 11/15 sin mejora Epoch 54/80 ---------------------------------------- Batch 10/200: Loss: 0.1061, PA: 0.9764, mIoU: 0.8462 Batch 20/200: Loss: 0.0989, PA: 0.9661, mIoU: 0.7988 Batch 30/200: Loss: 0.0876, PA: 0.9643, mIoU: 0.8105 Batch 40/200: Loss: 0.1155, PA: 0.9513, mIoU: 0.7935 Batch 50/200: Loss: 0.1089, PA: 0.9668, mIoU: 0.7799 Batch 60/200: Loss: 0.0536, PA: 0.9828, mIoU: 0.8849 Batch 70/200: Loss: 0.1000, PA: 0.9796, mIoU: 0.8781 Batch 80/200: Loss: 0.0889, PA: 0.9703, mIoU: 0.7921 Batch 90/200: Loss: 0.0575, PA: 0.9768, mIoU: 0.8881 Batch 100/200: Loss: 0.1285, PA: 0.9504, mIoU: 0.7717 Batch 110/200: Loss: 0.0559, PA: 0.9783, mIoU: 0.8930 Batch 120/200: Loss: 0.0709, PA: 0.9748, mIoU: 0.8362 Batch 130/200: Loss: 0.0481, PA: 0.9838, mIoU: 0.8790 Batch 140/200: Loss: 0.0742, PA: 0.9707, mIoU: 0.8325 Batch 150/200: Loss: 0.0880, PA: 0.9692, mIoU: 0.7952 Batch 160/200: Loss: 0.0608, PA: 0.9758, mIoU: 0.8592 Batch 170/200: Loss: 0.0659, PA: 0.9748, mIoU: 0.8543 Batch 180/200: Loss: 0.0993, PA: 0.9530, mIoU: 0.7625 Batch 190/200: Loss: 0.1416, PA: 0.9611, mIoU: 0.6156 Batch 200/200: Loss: 0.0513, PA: 0.9800, mIoU: 0.8951 Resumen Epoch 54: Tiempo: 401.31s Train Loss: 0.0938 | PA: 0.9708 | mIoU: 0.8139 Val Loss: 0.1755 | PA: 0.9515 | mIoU: 0.7245 Learning Rate: 0.000087 EarlyStopping: 12/15 sin mejora Epoch 55/80 ---------------------------------------- Batch 10/200: Loss: 0.0996, PA: 0.9681, mIoU: 0.7676 Batch 20/200: Loss: 0.0709, PA: 0.9773, mIoU: 0.8500 Batch 30/200: Loss: 0.0930, PA: 0.9726, mIoU: 0.7906 Batch 40/200: Loss: 0.0903, PA: 0.9650, mIoU: 0.8224 Batch 50/200: Loss: 0.0759, PA: 0.9780, mIoU: 0.8490 Batch 60/200: Loss: 0.0718, PA: 0.9699, mIoU: 0.8488 Batch 70/200: Loss: 0.0707, PA: 0.9764, mIoU: 0.8356 Batch 80/200: Loss: 0.1025, PA: 0.9775, mIoU: 0.7373 Batch 90/200: Loss: 0.1040, PA: 0.9592, mIoU: 0.7707 Batch 100/200: Loss: 0.1519, PA: 0.9314, mIoU: 0.6946 Batch 110/200: Loss: 0.1499, PA: 0.9461, mIoU: 0.6513 Batch 120/200: Loss: 0.0501, PA: 0.9817, mIoU: 0.8928 Batch 130/200: Loss: 0.0719, PA: 0.9766, mIoU: 0.8330 Batch 140/200: Loss: 0.0656, PA: 0.9765, mIoU: 0.8572 Batch 150/200: Loss: 0.0685, PA: 0.9741, mIoU: 0.8524 Batch 160/200: Loss: 0.1192, PA: 0.9705, mIoU: 0.8489 Batch 170/200: Loss: 0.0717, PA: 0.9702, mIoU: 0.8507 Batch 180/200: Loss: 0.0944, PA: 0.9624, mIoU: 0.7819 Batch 190/200: Loss: 0.0672, PA: 0.9732, mIoU: 0.8752 Batch 200/200: Loss: 0.0751, PA: 0.9757, mIoU: 0.8244 Resumen Epoch 55: Tiempo: 429.60s Train Loss: 0.0938 | PA: 0.9702 | mIoU: 0.8183 Val Loss: 0.1895 | PA: 0.9499 | mIoU: 0.7103 Learning Rate: 0.000081 EarlyStopping: 13/15 sin mejora Epoch 56/80 ---------------------------------------- Batch 10/200: Loss: 0.0944, PA: 0.9516, mIoU: 0.8415 Batch 20/200: Loss: 0.1242, PA: 0.9775, mIoU: 0.7767 Batch 30/200: Loss: 0.0958, PA: 0.9638, mIoU: 0.8101 Batch 40/200: Loss: 0.0814, PA: 0.9675, mIoU: 0.8162 Batch 50/200: Loss: 0.0533, PA: 0.9835, mIoU: 0.8808 Batch 60/200: Loss: 0.0835, PA: 0.9714, mIoU: 0.8305 Batch 70/200: Loss: 0.0678, PA: 0.9784, mIoU: 0.8728 Batch 80/200: Loss: 0.0632, PA: 0.9783, mIoU: 0.8447 Batch 90/200: Loss: 0.0670, PA: 0.9739, mIoU: 0.8582 Batch 100/200: Loss: 0.0959, PA: 0.9778, mIoU: 0.7522 Batch 110/200: Loss: 0.0767, PA: 0.9693, mIoU: 0.8462 Batch 120/200: Loss: 0.0724, PA: 0.9729, mIoU: 0.8570 Batch 130/200: Loss: 0.0670, PA: 0.9732, mIoU: 0.8553 Batch 140/200: Loss: 0.0646, PA: 0.9697, mIoU: 0.8966 Batch 150/200: Loss: 0.0683, PA: 0.9722, mIoU: 0.8625 Batch 160/200: Loss: 0.0602, PA: 0.9784, mIoU: 0.8682 Batch 170/200: Loss: 0.0560, PA: 0.9788, mIoU: 0.8813 Batch 180/200: Loss: 0.0842, PA: 0.9751, mIoU: 0.8303 Batch 190/200: Loss: 0.1055, PA: 0.9790, mIoU: 0.8512 Batch 200/200: Loss: 0.0816, PA: 0.9679, mIoU: 0.8255 Resumen Epoch 56: Tiempo: 412.13s Train Loss: 0.0859 | PA: 0.9725 | mIoU: 0.8263 Val Loss: 0.1920 | PA: 0.9484 | mIoU: 0.7081 Learning Rate: 0.000075 EarlyStopping: 14/15 sin mejora Epoch 57/80 ---------------------------------------- Batch 10/200: Loss: 0.0848, PA: 0.9725, mIoU: 0.8018 Batch 20/200: Loss: 0.0763, PA: 0.9746, mIoU: 0.8289 Batch 30/200: Loss: 0.0881, PA: 0.9644, mIoU: 0.7900 Batch 40/200: Loss: 0.1133, PA: 0.9736, mIoU: 0.8515 Batch 50/200: Loss: 0.1407, PA: 0.9624, mIoU: 0.6702 Batch 60/200: Loss: 0.0579, PA: 0.9796, mIoU: 0.8679 Batch 70/200: Loss: 0.0853, PA: 0.9649, mIoU: 0.8218 Batch 80/200: Loss: 0.0863, PA: 0.9685, mIoU: 0.8358 Batch 90/200: Loss: 0.1733, PA: 0.9349, mIoU: 0.7431 Batch 100/200: Loss: 0.1618, PA: 0.9537, mIoU: 0.7140 Batch 110/200: Loss: 0.1136, PA: 0.9761, mIoU: 0.8193 Batch 120/200: Loss: 0.0616, PA: 0.9774, mIoU: 0.8585 Batch 130/200: Loss: 0.0603, PA: 0.9787, mIoU: 0.8813 Batch 140/200: Loss: 0.0520, PA: 0.9786, mIoU: 0.8805 Batch 150/200: Loss: 0.0747, PA: 0.9718, mIoU: 0.8459 Batch 160/200: Loss: 0.0764, PA: 0.9690, mIoU: 0.8367 Batch 170/200: Loss: 0.0848, PA: 0.9659, mIoU: 0.8229 Batch 180/200: Loss: 0.0706, PA: 0.9739, mIoU: 0.8485 Batch 190/200: Loss: 0.1065, PA: 0.9769, mIoU: 0.8514 Batch 200/200: Loss: 0.0705, PA: 0.9714, mIoU: 0.8659 Resumen Epoch 57: Tiempo: 406.61s Train Loss: 0.0878 | PA: 0.9718 | mIoU: 0.8275 Val Loss: 0.1880 | PA: 0.9488 | mIoU: 0.7136 Learning Rate: 0.000069 EarlyStopping: 15/15 sin mejora ============================================================ EARLY STOPPING ACTIVADO Sin mejora significativa por 15 épocas Mejor mIoU alcanzado: 0.7260 Entrenamiento detenido en época 57 ============================================================
¡Entrenamiento completado exitosamente! Historial guardado. Mejor mIoU: 0.7260
In [229]:
train_acc_final = history['train_pa'][-1]
val_acc_final = history['val_pa'][-1]
print(f"Train Accuracy final: {train_acc_final:.4f}")
print(f"Val/Test Accuracy final: {val_acc_final:.4f}")
best_epoch = np.argmax(history['val_miou'])
train_acc_best = history['train_pa'][best_epoch]
val_acc_best = history['val_pa'][best_epoch]
print(f"Mejor época: {best_epoch + 1}")
print(f"Train Accuracy (mejor época): {train_acc_best:.4f}")
print(f"Val/Test Accuracy (mejor época): {val_acc_best:.4f}")
Train Accuracy final: 0.9718 Val/Test Accuracy final: 0.9488 Mejor época: 42 Train Accuracy (mejor época): 0.9655 Val/Test Accuracy (mejor época): 0.9523
In [230]:
def plot_accuracy(history):
plt.figure(figsize=(8,5))
plt.plot(history['train_pa'], label='Train Accuracy')
plt.plot(history['val_pa'], label='Val/Test Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Pixel Accuracy')
plt.title('Accuracy (Pixel Accuracy)')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
plot_accuracy(history)
In [231]:
def evaluate_accuracy(model, test_loader, device, n_cls, ignore_index):
model.eval()
total_pa = 0
num_batches = 0
with torch.no_grad():
for images, masks in test_loader:
images = images.to(device)
masks = masks.to(device)
outputs = model(images)
metrics = Metrics(outputs, masks, None,
n_cls=n_cls,
ignore_index=ignore_index)
total_pa += metrics.PA()
num_batches += 1
return total_pa / num_batches
In [232]:
test_accuracy = evaluate_accuracy(
model,
test_dl,
device="cpu",
n_cls=n_cls,
ignore_index=255
)
print(f"Test Accuracy final: {test_accuracy:.4f}")
Test Accuracy final: 0.9508
In [233]:
def plot_accuracy_with_test(history, test_accuracy):
epochs = range(1, len(history['train_pa']) + 1)
plt.figure(figsize=(8,5))
plt.plot(epochs, history['train_pa'], label='Train Accuracy')
plt.plot(epochs, history['val_pa'], label='Val Accuracy')
# Línea horizontal del test
plt.hlines(
y=test_accuracy,
xmin=1,
xmax=len(epochs),
colors='red',
linestyles='dashed',
label=f'Test Accuracy = {test_accuracy:.4f}'
)
plt.xlabel('Epoch')
plt.ylabel('Pixel Accuracy')
plt.title('Accuracy: Train vs Val vs Test')
plt.legend()
plt.grid(alpha=0.3)
plot_accuracy_with_test(history, test_accuracy)
In [199]:
CLASS_NAMES = {
0: "background",
1: "topwear",
2: "lowerwear",
3: "dress",
4: "footwear",
5: "body",
}
In [200]:
@torch.no_grad()
def predict_mask(model, image, device):
"""
image: tensor (3,H,W)
return: tensor (H,W) con clases predichas
"""
model.eval()
image = image.unsqueeze(0).to(device) # (1,3,H,W)
outputs = model(image)
pred = torch.argmax(outputs, dim=1) # (1,H,W)
return pred.squeeze(0).cpu()
def get_present_classes(mask, n_cls, ignore_index=255):
"""
Devuelve lista de clases presentes en una máscara
"""
if torch.is_tensor(mask):
vals = torch.unique(mask).cpu().numpy()
else:
vals = np.unique(mask)
classes = [int(v) for v in vals if v != ignore_index and v < n_cls]
return sorted(classes)
def visualize_prediction_sample(
model,
dataset,
n_samples=6,
device="cpu"
):
"""
Visualiza:
Imagen | Máscara GT | Máscara Predicha
"""
import math
model.eval()
# get number of classes / ignore index from dataset if available
n_cls = dataset.dataset.n_cls if hasattr(dataset, "dataset") else getattr(dataset, "n_cls", n_cls)
ignore_index = dataset.dataset.ignore_index if hasattr(dataset, "dataset") else getattr(dataset, "ignore_index", 255)
total_plots = n_samples * 3
cols = 3
rows = math.ceil(total_plots / cols)
fig, axs = plt.subplots(rows, cols, figsize=(18, rows * 3))
axs = axs.flatten()
indices = random.sample(range(len(dataset)), n_samples)
i = 0
for idx in indices:
image, gt = dataset[idx]
# Imagen original
rgb = to_numpy_image(image.float())
# GT mask (RGB)
gt_rgb = mask_to_rgb(
gt,
dataset.dataset.n_cls if hasattr(dataset, "dataset") else n_cls,
dataset.dataset.ignore_index if hasattr(dataset, "dataset") else ignore_index
)
# Predicción (mask + RGB)
pred = predict_mask(model, image, device)
pred_rgb = mask_to_rgb(
pred,
dataset.dataset.n_cls if hasattr(dataset, "dataset") else n_cls,
dataset.dataset.ignore_index if hasattr(dataset, "dataset") else ignore_index
)
# clases presentes en GT y Pred
gt_classes = get_present_classes(gt, n_cls, ignore_index)
pred_classes = get_present_classes(pred, n_cls, ignore_index)
gt_names = [CLASS_NAMES[c] for c in gt_classes]
pred_names = [CLASS_NAMES[c] for c in pred_classes]
# mostrar con títulos que incluyen las clases presentes
plot(axs[i], rgb, "Imagen")
i += 1
plot(axs[i], gt_rgb, f"GT\n{gt_names}")
i += 1
plot(axs[i], pred_rgb, f"Predicción\n{pred_names}")
i += 1
# Títulos con clases
# gt_title = f"GT\ncls: {gt_classes}"
# pred_title = f"Predicción\ncls: {pred_classes}"
for j in range(i, len(axs)):
axs[j].axis("off")
plt.suptitle(
"Visualización de Segmentación: Imagen | GT | Predicción",
fontsize=16
)
plt.tight_layout()
plt.show()
print("=" * 60)
print("VISUALIZANDO PREDICCIONES EN VALIDACIÓN")
print("=" * 60)
visualize_prediction_sample(
model=model,
dataset=val_dl.dataset,
n_samples=6,
device=device
)
VISUALIZANDO PREDICCIONES EN VALIDACIÓN ============================================================
============================================================
In [201]:
# Si aún no tienes esta función, aquí está mask_to_rgb mejorada
def mask_to_rgb(mask: torch.Tensor, n_cls: int, ignore_index: int = 255) -> np.ndarray:
"""
Convierte máscara de índices a RGB usando el colormap adecuado
Args:
mask: tensor (H,W) con índices de clase
n_cls: número de clases
ignore_index: valor a ignorar
Returns:
np.ndarray (H,W,3) en RGB
"""
# Paleta de colores (ajusta según tu dataset)
PALETTE = [
[0, 0, 0], # 0 background → negro
[220, 20, 60], # 1 topwear → rojo (crimson)
[30, 144, 255], # 2 lowerwear → azul
[255, 165, 0], # 3 dress → naranja
[138, 43, 226], # 4 footwear → violeta
[46, 139, 87], # 5 body → verde (sea green)
]
# Asegurar que tenemos colores para todas las clases
if len(PALETTE) < n_cls:
PALETTE.extend([[0, 0, 0]] * (n_cls - len(PALETTE)))
if torch.is_tensor(mask):
mask_np = mask.cpu().numpy().astype(np.uint8)
else:
mask_np = mask.astype(np.uint8)
# Crear imagen RGB
h, w = mask_np.shape
rgb = np.zeros((h, w, 3), dtype=np.uint8)
for class_idx in range(n_cls):
rgb[mask_np == class_idx] = PALETTE[class_idx]
# Ignorar índice (si existe)
if ignore_index < 255: # Solo si no es 255
rgb[mask_np == ignore_index] = [255, 255, 255] # Blanco para ignorar
return rgb
def get_class_names(classes: List[int]) -> List[str]:
"""
Devuelve nombres de clases basados en índices
Args:
classes: lista de índices de clase
Returns:
Lista de nombres de clase
"""
return [CLASS_NAMES[c] if c < len(CLASS_NAMES) else f"clase_{c}"
for c in classes]
def create_legend(classes: List[int], palette: List[List[int]]) -> List[mpatches.Patch]:
"""
Crea leyenda para las clases presentes
Args:
classes: lista de índices de clase
palette: lista de colores RGB
Returns:
Lista de patches para la leyenda
"""
class_names = get_class_names(classes)
patches = []
for class_idx, class_name in zip(classes, class_names):
color = [c/255 for c in palette[class_idx]] # Normalizar a [0,1]
patch = mpatches.Patch(color=color, label=f"{class_idx}: {class_name}")
patches.append(patch)
return patches
@torch.no_grad()
def predict_from_image(
model,
image_path: str,
transform,
device: str = "cpu",
n_cls: int = 8,
ignore_index: int = 255,
show_legend: bool = True,
show_overlay: bool = True,
overlay_alpha: float = 0.4,
figsize: Tuple[int, int] = (18, 8)
) -> Tuple[torch.Tensor, List[int], np.ndarray]:
"""
Prueba el modelo con una imagen cargada desde disco con visualización mejorada
Args:
model: modelo entrenado
image_path: ruta a la imagen (jpg/png)
transform: mismas transforms usadas en el dataset
device: cpu / cuda
n_cls: número de clases
ignore_index: índice ignorado
show_legend: mostrar leyenda de clases
show_overlay: mostrar overlay predicción/imagen
overlay_alpha: transparencia del overlay
figsize: tamaño de la figura
Returns:
Tuple: (máscara predicha, clases presentes, imagen original)
"""
model.eval()
# -------------------------------------------------
# 1. Cargar imagen
# -------------------------------------------------
img_pil = Image.open(image_path).convert("RGB")
img_np = np.array(img_pil)
original_size = img_np.shape[:2] # Guardar tamaño original
# -------------------------------------------------
# 2. Transformaciones
# -------------------------------------------------
transformed = transform(image=img_np)
img_t = transformed["image"] # tensor (3,H,W)
img_t = img_t.unsqueeze(0).to(device)
# -------------------------------------------------
# 3. Predicción
# -------------------------------------------------
outputs = model(img_t)
pred = torch.argmax(outputs, dim=1).squeeze(0).cpu()
# Redimensionar a tamaño original si es necesario
if pred.shape != original_size:
pred_np = pred.numpy().astype(np.uint8)
pred_resized = cv2.resize(pred_np, (original_size[1], original_size[0]),
interpolation=cv2.INTER_NEAREST)
pred = torch.from_numpy(pred_resized)
# -------------------------------------------------
# 4. Convertir a RGB
# -------------------------------------------------
pred_rgb = mask_to_rgb(pred, n_cls, ignore_index)
# -------------------------------------------------
# 5. Clases presentes
# -------------------------------------------------
present_classes = sorted([
int(v) for v in torch.unique(pred)
if v != ignore_index and v < n_cls
])
present_names = get_class_names(present_classes)
# -------------------------------------------------
# 6. Preparar visualización
# -------------------------------------------------
n_cols = 3 if show_overlay else 2
fig, axes = plt.subplots(1, n_cols, figsize=figsize)
if n_cols == 2:
ax_img, ax_pred = axes
else:
ax_img, ax_pred, ax_overlay = axes
# Imagen original
ax_img.imshow(img_np)
ax_img.set_title("Imagen Original", fontsize=14, fontweight='bold')
ax_img.axis('off')
# Predicción
ax_pred.imshow(pred_rgb)
pred_title = "Predicción"
if present_classes:
pred_title += f"\nClases: {present_classes}\n{', '.join(present_names)}"
ax_pred.set_title(pred_title, fontsize=14, fontweight='bold')
ax_pred.axis('off')
# Overlay (opcional)
if show_overlay:
# Asegurar mismo tamaño
if pred_rgb.shape[:2] != img_np.shape[:2]:
pred_rgb = cv2.resize(pred_rgb, (img_np.shape[1], img_np.shape[0]),
interpolation=cv2.INTER_NEAREST)
overlay = cv2.addWeighted(
img_np, 1 - overlay_alpha,
pred_rgb, overlay_alpha,
0
)
ax_overlay.imshow(overlay)
ax_overlay.set_title(f"Overlay (α={overlay_alpha})",
fontsize=14, fontweight='bold')
ax_overlay.axis('off')
# -------------------------------------------------
# 7. Leyenda (opcional)
# -------------------------------------------------
if show_legend and present_classes:
# Paleta (debe coincidir con mask_to_rgb)
PALETTE = CLASS_COLORS
# Crear leyenda como subplot separado o en la figura
legend_patches = create_legend(present_classes, PALETTE[:n_cls])
# Agregar leyenda en una posición adecuada
plt.figlegend(
handles=legend_patches,
loc='lower center',
ncol=min(4, len(present_classes)),
fontsize=10,
title="Leyenda de Clases",
title_fontsize=11,
bbox_to_anchor=(0.5, -0.05)
)
plt.suptitle(
f"Segmentación Semántica - {image_path.split('/')[-1]}",
fontsize=16,
fontweight='bold',
y=1.02
)
plt.tight_layout()
plt.show()
# -------------------------------------------------
# 8. Información por consola
# -------------------------------------------------
print("=" * 60)
print("INFORMACIÓN DE PREDICCIÓN")
print("=" * 60)
print(f"Archivo: {image_path}")
print(f"Tamaño original: {original_size}")
print(f"Tamaño predicha: {pred.shape}")
print(f"Clases detectadas: {present_classes}")
print(f"Nombres: {present_names}")
print(f"Total píxeles: {pred.numel()}")
# Distribución de clases
if present_classes:
print("\nDistribución de píxeles por clase:")
for class_idx in present_classes:
count = (pred == class_idx).sum().item()
percentage = (count / pred.numel()) * 100
class_name = get_class_names([class_idx])[0]
print(f" Clase {class_idx} ({class_name}): {count:,} píxeles ({percentage:.2f}%)")
print("=" * 60)
return pred, present_classes, img_np
# # Versión alternativa más compacta si prefieres menos detalles
# @torch.no_grad()
# def predict_from_image_simple(
# model,
# image_path: str,
# transform,
# device: str = "cpu",
# n_cls: int = 8,
# ignore_index: int = 255
# ) -> Tuple[torch.Tensor, List[int]]:
# """
# Versión simplificada similar a visualize_prediction_sample
# """
# model.eval()
# # Cargar y transformar
# img_pil = Image.open(image_path).convert("RGB")
# img_np = np.array(img_pil)
# transformed = transform(image=img_np)
# img_t = transformed["image"].unsqueeze(0).to(device)
# # Predecir
# outputs = model(img_t)
# pred = torch.argmax(outputs, dim=1).squeeze(0).cpu()
# # Clases presentes
# present_classes = sorted([
# int(v) for v in torch.unique(pred)
# if v != ignore_index and v < n_cls
# ])
# # Visualización estilo dataset
# pred_rgb = mask_to_rgb(pred, n_cls, ignore_index)
# fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# axes[0].imshow(img_np)
# axes[0].set_title("Imagen", fontsize=12)
# axes[0].axis('off')
# axes[1].imshow(pred_rgb)
# title = f"Predicción"
# if present_classes:
# names = get_class_names(present_classes)
# title += f"\nClases: {present_classes}\n{', '.join(names)}"
# axes[1].set_title(title, fontsize=12)
# axes[1].axis('off')
# plt.tight_layout()
# plt.show()
# return pred, present_classes
In [234]:
image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\pondoy.png"
#image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\vialpando.png"
pred_mask, classes, original_img = predict_from_image(
model=model,
image_path=image_path,
transform=val_tf, # ← IMPORTANTE
device="cpu",
n_cls=6,
ignore_index=255,
show_legend=True,
show_overlay=True,
overlay_alpha=0.4
)
# # Versión simplificada (más parecida al dataset)
# pred_mask, classes = predict_from_image_simple(
# model=model,
# image_path=image_path,
# transform=transform,
# device=device,
# n_cls=n_cls
# )
============================================================ INFORMACIÓN DE PREDICCIÓN ============================================================ Archivo: C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\pondoy.png Tamaño original: (799, 532) Tamaño predicha: torch.Size([799, 532]) Clases detectadas: [0, 1, 2, 4, 5] Nombres: ['background', 'topwear', 'lowerwear', 'footwear', 'body'] Total píxeles: 425068 Distribución de píxeles por clase: Clase 0 (background): 324,904 píxeles (76.44%) Clase 1 (topwear): 31,348 píxeles (7.37%) Clase 2 (lowerwear): 44,379 píxeles (10.44%) Clase 4 (footwear): 2,849 píxeles (0.67%) Clase 5 (body): 21,588 píxeles (5.08%) ============================================================
In [235]:
#image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\pondoy.png"
image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\vialpando.png"
pred_mask, classes, original_img = predict_from_image(
model=model,
image_path=image_path,
transform=val_tf, # ← IMPORTANTE
device="cpu",
n_cls=6,
ignore_index=255,
show_legend=True,
show_overlay=True,
overlay_alpha=0.4
)
# # Versión simplificada (más parecida al dataset)
# pred_mask, classes = predict_from_image_simple(
# model=model,
# image_path=image_path,
# transform=transform,
# device=device,
# n_cls=n_cls
# )
============================================================ INFORMACIÓN DE PREDICCIÓN ============================================================ Archivo: C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\vialpando.png Tamaño original: (4480, 3168) Tamaño predicha: torch.Size([4480, 3168]) Clases detectadas: [0, 1, 2, 4, 5] Nombres: ['background', 'topwear', 'lowerwear', 'footwear', 'body'] Total píxeles: 14192640 Distribución de píxeles por clase: Clase 0 (background): 11,308,681 píxeles (79.68%) Clase 1 (topwear): 820,623 píxeles (5.78%) Clase 2 (lowerwear): 1,301,940 píxeles (9.17%) Clase 4 (footwear): 144,311 píxeles (1.02%) Clase 5 (body): 617,085 píxeles (4.35%) ============================================================
In [ ]:
image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\naked.jpeg"
pred_mask, classes, original_img = predict_from_image(
model=model,
image_path=image_path,
transform=val_tf, # ← IMPORTANTE
device="cpu",
n_cls=6,
ignore_index=255,
show_legend=True,
show_overlay=True,
overlay_alpha=0.4
)
In [203]:
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
@torch.no_grad()
def compute_confusion_matrix(
model,
dataloader,
n_cls,
device="cpu",
ignore_index=255
):
"""
Calcula la matriz de confusión por píxel para segmentación semántica
"""
model.eval()
all_preds = []
all_gts = []
for images, gts in dataloader:
images = images.to(device)
gts = gts.to(device)
outputs = model(images) # (B, C, H, W)
preds = torch.argmax(outputs, dim=1) # (B, H, W)
# Aplanar
preds = preds.view(-1)
gts = gts.view(-1)
# Filtrar ignore_index
mask = gts != ignore_index
preds = preds[mask]
gts = gts[mask]
all_preds.append(preds.cpu().numpy())
all_gts.append(gts.cpu().numpy())
all_preds = np.concatenate(all_preds)
all_gts = np.concatenate(all_gts)
cm = confusion_matrix(
all_gts,
all_preds,
labels=list(range(n_cls))
)
return cm
In [204]:
def plot_confusion_matrix(cm, class_names=None, normalize=True):
"""
Visualiza la matriz de confusión
"""
if normalize:
cm = cm.astype("float") / (cm.sum(axis=1, keepdims=True) + 1e-8)
plt.figure(figsize=(8, 6))
sns.heatmap(
cm,
annot=True,
fmt=".2f" if normalize else "d",
cmap="Blues",
xticklabels=class_names,
yticklabels=class_names
)
plt.xlabel("Predicción")
plt.ylabel("Ground Truth")
plt.title("Matriz de Confusión (Segmentación)")
plt.tight_layout()
plt.show()
In [237]:
print("="*60)
print("CALCULANDO MATRIZ DE CONFUSIÓN (VALIDACIÓN)")
print("="*60)
cm = compute_confusion_matrix(
model=model,
dataloader=val_dl,
n_cls=n_cls,
device=device,
ignore_index=255
)
class_names = CLASS_NAMES.values()
plot_confusion_matrix(cm, class_names=class_names, normalize=True)
============================================================ CALCULANDO MATRIZ DE CONFUSIÓN (VALIDACIÓN) ============================================================
In [206]:
def compute_iou_per_class(model, dataloader, n_cls, device="cpu", ignore_index=255):
model.eval()
intersection = torch.zeros(n_cls)
union = torch.zeros(n_cls)
with torch.no_grad():
for images, gts in dataloader:
images = images.to(device)
gts = gts.to(device)
outputs = model(images)
preds = torch.argmax(outputs, dim=1)
mask = gts != ignore_index
for cls in range(n_cls):
pred_c = (preds == cls) & mask
gt_c = (gts == cls) & mask
intersection[cls] += (pred_c & gt_c).sum().cpu()
union[cls] += (pred_c | gt_c).sum().cpu()
iou_per_class = {}
for cls in range(n_cls):
if union[cls] > 0:
iou_per_class[f"class_{cls}"] = (intersection[cls] / union[cls]).item()
else:
iou_per_class[f"class_{cls}"] = 0.0
return iou_per_class
In [207]:
iou_per_class = compute_iou_per_class(
model=model,
dataloader=val_dl,
n_cls=n_cls,
device=device,
ignore_index=255
)
iou_per_class
Out[207]:
{'class_0': 0.9797448515892029,
'class_1': 0.749193549156189,
'class_2': 0.6017902493476868,
'class_3': 0.42478734254837036,
'class_4': 0.6826684474945068,
'class_5': 0.7988145351409912}
In [208]:
def plot_iou_per_class(iou_dict):
plt.figure(figsize=(8, 5))
plt.bar(iou_dict.keys(), iou_dict.values())
plt.ylabel("IoU")
plt.xlabel("Clase")
plt.title("IoU por Clase")
plt.ylim(0, 1)
plt.grid(axis="y", alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
plot_iou_per_class(iou_per_class)
In [209]:
from sklearn.metrics import precision_score, recall_score, f1_score
def compute_precision_recall_f1_per_class(
model,
dataloader,
n_cls,
device="cpu",
ignore_index=255
):
model.eval()
all_preds = []
all_gts = []
with torch.no_grad():
for images, gts in dataloader:
images = images.to(device)
gts = gts.to(device)
outputs = model(images)
preds = torch.argmax(outputs, dim=1)
preds = preds.view(-1)
gts = gts.view(-1)
mask = gts != ignore_index
all_preds.append(preds[mask].cpu())
all_gts.append(gts[mask].cpu())
y_pred = torch.cat(all_preds).numpy()
y_true = torch.cat(all_gts).numpy()
precision = precision_score(
y_true, y_pred,
labels=list(range(n_cls)),
average=None,
zero_division=0
)
recall = recall_score(
y_true, y_pred,
labels=list(range(n_cls)),
average=None,
zero_division=0
)
f1 = f1_score(
y_true, y_pred,
labels=list(range(n_cls)),
average=None,
zero_division=0
)
metrics_dict = {
"precision": {f"class_{i}": precision[i] for i in range(n_cls)},
"recall": {f"class_{i}": recall[i] for i in range(n_cls)},
"f1": {f"class_{i}": f1[i] for i in range(n_cls)},
}
return metrics_dict
In [210]:
metrics_dict = compute_precision_recall_f1_per_class(
model=model,
dataloader=val_dl,
n_cls=n_cls,
device=device,
ignore_index=255
)
print(metrics_dict)
{'precision': {'class_0': np.float64(0.9920547748523842), 'class_1': np.float64(0.8438798264754676), 'class_2': np.float64(0.6954297107199435), 'class_3': np.float64(0.7076170681012349), 'class_4': np.float64(0.7288585964419577), 'class_5': np.float64(0.8911843407499725)}, 'recall': {'class_0': np.float64(0.987493335482388), 'class_1': np.float64(0.8697424354030954), 'class_2': np.float64(0.8171612860102935), 'class_3': np.float64(0.5152181460479112), 'class_4': np.float64(0.9150540404930771), 'class_5': np.float64(0.8851494520697565)}, 'f1': {'class_0': np.float64(0.9897687997434291), 'class_1': np.float64(0.856615967000465), 'class_2': np.float64(0.751397090119035), 'class_3': np.float64(0.5962817388975031), 'class_4': np.float64(0.8114117364117364), 'class_5': np.float64(0.8881566449915979)}}
In [211]:
def plot_precision_recall_f1(metrics_dict):
classes = list(metrics_dict["precision"].keys())
p = list(metrics_dict["precision"].values())
r = list(metrics_dict["recall"].values())
f = list(metrics_dict["f1"].values())
x = np.arange(len(classes))
width = 0.25
plt.figure(figsize=(10, 5))
plt.bar(x - width, p, width, label="Precision")
plt.bar(x, r, width, label="Recall")
plt.bar(x + width, f, width, label="F1-score")
plt.xticks(x, classes, rotation=45)
plt.ylim(0, 1)
plt.ylabel("Score")
plt.title("Precision / Recall / F1 por Clase")
plt.legend()
plt.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
plot_precision_recall_f1(metrics_dict)
In [212]:
def visualize_error_map(image, gt, pred):
"""
image: (H,W,3)
gt, pred: (H,W)
"""
error = (gt != pred)
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(image)
plt.title("Imagen")
plt.axis("off")
plt.subplot(1, 3, 2)
plt.imshow(error, cmap="Reds")
plt.title("Mapa de Error")
plt.axis("off")
plt.subplot(1, 3, 3)
overlay = image.copy()
overlay[error] = [255, 0, 0]
plt.imshow(overlay)
plt.title("Errores Superpuestos")
plt.axis("off")
plt.tight_layout()
plt.show()
In [213]:
def run_error_map_from_loader(
model,
dataloader,
device="cpu",
ignore_index=255
):
model.eval()
images, gts = next(iter(dataloader))
images = images.to(device)
gts = gts.to(device)
with torch.no_grad():
outputs = model(images)
preds = torch.argmax(outputs, dim=1)
# TOMAMOS SOLO LA PRIMERA IMAGEN DEL BATCH
img = images[0].cpu()
gt = gts[0].cpu()
pred = preds[0].cpu()
# ---- Desnormalizar imagen (ImageNet) ----
img = img.permute(1, 2, 0).numpy()
img = (img - img.min()) / (img.max() - img.min())
img = (img * 255).astype(np.uint8)
gt = gt.numpy()
pred = pred.numpy()
# Ignorar ignore_index en visualización
mask = gt != ignore_index
gt = np.where(mask, gt, 0)
pred = np.where(mask, pred, 0)
visualize_error_map(img, gt, pred)
In [214]:
run_error_map_from_loader(
model=model,
dataloader=val_dl,
device=device,
ignore_index=255
)
SEPARACION DE PRENDAS Y COLOR¶
In [215]:
import cv2
import numpy as np
image_path = r"C:\Users\pc\Desktop\Proyecto_Segmentacion\Imagen_eval\vialpando.png"
# Cargar imagen
img_bgr = cv2.imread(image_path)
# Validar
assert img_bgr is not None, "Imagen no encontrada"
# Convertir BGR → RGB
img_np = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
print(img_np.shape, img_np.dtype)
(4480, 3168, 3) uint8
In [216]:
@torch.no_grad()
def predict_mask(model, image_tensor, device):
model.eval()
image_tensor = image_tensor.unsqueeze(0).to(device)
outputs = model(image_tensor)
pred = torch.argmax(outputs, dim=1)
return pred.squeeze(0).cpu().numpy()
pred_mask # (H, W) con clases
Out[216]:
tensor([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=torch.uint8)
In [217]:
def get_garment_mask(pred_mask, class_id):
"""
pred_mask: (H,W)
class_id: int (ej: camiseta)
return: mask (H,W) uint8 para LaMa
"""
# 1. Zona NO prenda = 255 (a rellenar)
mask = np.ones_like(pred_mask, dtype=np.uint8) * 255
# 2. Zona prenda = 0 (se conserva)
mask[pred_mask == class_id] = 0
return mask
In [218]:
def clean_mask(mask):
kernel = np.ones((7, 7), np.uint8)
# Eliminar agujeros
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# Suavizar bordes
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
return mask
In [219]:
mask = get_garment_mask(pred_mask, class_id=1) # camiseta
mask = clean_mask(mask)
In [220]:
def show_mask(image, mask):
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.imshow(image)
plt.title("Imagen")
plt.axis("off")
plt.subplot(1,2,2)
plt.imshow(mask, cmap="gray")
plt.title("Máscara para LaMa (blanco = rellenar)")
plt.axis("off")
plt.show()
In [221]:
show_mask(img_np, mask)
cv2.imwrite("input_image.png", cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR))
cv2.imwrite("input_mask.png", mask)
Out[221]:
True
In [222]:
%pip install opencv-python matplotlib
Requirement already satisfied: opencv-python in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (4.12.0.88) Requirement already satisfied: matplotlib in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (3.10.8) Requirement already satisfied: numpy<2.3.0,>=2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from opencv-python) (2.2.6) Requirement already satisfied: contourpy>=1.0.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (1.3.3) Requirement already satisfied: cycler>=0.10 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (4.61.0) Requirement already satisfied: kiwisolver>=1.3.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (1.4.9) Requirement already satisfied: packaging>=20.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (25.0) Requirement already satisfied: pillow>=8 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (12.0.0) Requirement already satisfied: pyparsing>=3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (3.2.5) Requirement already satisfied: python-dateutil>=2.7 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from matplotlib) (2.9.0.post0) Requirement already satisfied: six>=1.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from python-dateutil>=2.7->matplotlib) (1.17.0) Note: you may need to restart the kernel to use updated packages.
In [223]:
%pip install numpy cython
%pip install scikit-image
Requirement already satisfied: numpy in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.2.6) Requirement already satisfied: cython in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (3.2.3) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: scikit-image in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (0.25.2) Requirement already satisfied: numpy>=1.24 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (2.2.6) Requirement already satisfied: scipy>=1.11.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (1.16.3) Requirement already satisfied: networkx>=3.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (3.6.1) Requirement already satisfied: pillow>=10.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (12.0.0) Requirement already satisfied: imageio!=2.35.0,>=2.33 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (2.37.2) Requirement already satisfied: tifffile>=2022.8.12 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (2025.12.12) Requirement already satisfied: packaging>=21 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (25.0) Requirement already satisfied: lazy-loader>=0.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from scikit-image) (0.4) Note: you may need to restart the kernel to use updated packages.
In [224]:
%pip install torch torchvision
%pip install albumentations
%pip install omegaconf
%pip install tqdm
Requirement already satisfied: torch in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.9.1) Requirement already satisfied: torchvision in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (0.24.1) Requirement already satisfied: filelock in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.20.0) Requirement already satisfied: typing-extensions>=4.10.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (4.15.0) Requirement already satisfied: sympy>=1.13.3 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (1.14.0) Requirement already satisfied: networkx>=2.5.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.6.1) Requirement already satisfied: jinja2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (3.1.6) Requirement already satisfied: fsspec>=0.8.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (2025.12.0) Requirement already satisfied: setuptools in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torch) (80.9.0) Requirement already satisfied: numpy in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torchvision) (2.2.6) Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from torchvision) (12.0.0) Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from sympy>=1.13.3->torch) (1.3.0) Requirement already satisfied: MarkupSafe>=2.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from jinja2->torch) (3.0.3) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: albumentations in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.0.8) Requirement already satisfied: numpy>=1.24.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (2.2.6) Requirement already satisfied: scipy>=1.10.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (1.16.3) Requirement already satisfied: PyYAML in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (6.0.3) Requirement already satisfied: pydantic>=2.9.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (2.12.5) Requirement already satisfied: albucore==0.0.24 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (0.0.24) Requirement already satisfied: opencv-python-headless>=4.9.0.80 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albumentations) (4.12.0.88) Requirement already satisfied: stringzilla>=3.10.4 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albucore==0.0.24->albumentations) (4.4.0) Requirement already satisfied: simsimd>=5.9.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from albucore==0.0.24->albumentations) (6.5.3) Requirement already satisfied: annotated-types>=0.6.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (0.7.0) Requirement already satisfied: pydantic-core==2.41.5 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (2.41.5) Requirement already satisfied: typing-extensions>=4.14.1 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (4.15.0) Requirement already satisfied: typing-inspection>=0.4.2 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from pydantic>=2.9.2->albumentations) (0.4.2) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: omegaconf in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (2.3.0) Requirement already satisfied: antlr4-python3-runtime==4.9.* in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from omegaconf) (4.9.3) Requirement already satisfied: PyYAML>=5.1.0 in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from omegaconf) (6.0.3) Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: tqdm in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (4.67.1) Requirement already satisfied: colorama in c:\users\pc\desktop\proyecto_segmentacion\.venv\lib\site-packages (from tqdm) (0.4.6) Note: you may need to restart the kernel to use updated packages.
In [225]:
!mkdir -p pretrained
A subdirectory or file -p already exists. Error occurred while processing: -p. A subdirectory or file pretrained already exists. Error occurred while processing: pretrained.
In [226]:
# Imagen inpainted (sin camiseta)
inpainted = cv2.imread(r"C:\Users\pc\Desktop\Proyecto_Segmentacion\input_mask.png")
inpainted = cv2.cvtColor(inpainted, cv2.COLOR_BGR2RGB)
In [227]:
import matplotlib.pyplot as plt
plt.figure(figsize=(12,4))
plt.subplot(1,3,1)
plt.imshow(img_np)
plt.title("Original")
plt.axis("off")
plt.subplot(1,3,2)
plt.imshow(mask, cmap="gray")
plt.title("Máscara (prenda)")
plt.axis("off")
plt.subplot(1,3,3)
plt.imshow(inpainted)
plt.title("Rellenado con LaMa")
plt.axis("off")
plt.tight_layout()
plt.show()